@@ -44,7 +44,7 @@ use crate::borrow_check::{
4444
4545use self :: values:: { LivenessValues , RegionValueElements , RegionValues } ;
4646use super :: universal_regions:: UniversalRegions ;
47- use super :: ToRegionVid ;
47+ use super :: { PoloniusOutput , ToRegionVid } ;
4848
4949mod dump_mir;
5050mod graphviz;
@@ -484,6 +484,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
484484 upvars : & [ Upvar ] ,
485485 mir_def_id : DefId ,
486486 errors_buffer : & mut Vec < Diagnostic > ,
487+ polonius_output : Option < Rc < PoloniusOutput > > ,
487488 ) -> Option < ClosureRegionRequirements < ' tcx > > {
488489 self . propagate_constraints ( body) ;
489490
@@ -509,16 +510,33 @@ impl<'tcx> RegionInferenceContext<'tcx> {
509510 // multiple problems.
510511 let mut region_naming = RegionErrorNamingCtx :: new ( ) ;
511512
512- self . check_universal_regions (
513- infcx,
514- body,
515- local_names,
516- upvars,
517- mir_def_id,
518- outlives_requirements. as_mut ( ) ,
519- errors_buffer,
520- & mut region_naming,
521- ) ;
513+ // In Polonius mode, the errors about missing universal region relations are in the output
514+ // and need to be emitted or propagated. Otherwise, we need to check whether the
515+ // constraints were too strong, and if so, emit or propagate those errors.
516+ if infcx. tcx . sess . opts . debugging_opts . polonius {
517+ self . check_polonius_subset_errors (
518+ infcx,
519+ body,
520+ local_names,
521+ upvars,
522+ mir_def_id,
523+ outlives_requirements. as_mut ( ) ,
524+ errors_buffer,
525+ & mut region_naming,
526+ polonius_output. expect ( "Polonius output is unavailable despite `-Z polonius`" ) ,
527+ ) ;
528+ } else {
529+ self . check_universal_regions (
530+ infcx,
531+ body,
532+ local_names,
533+ upvars,
534+ mir_def_id,
535+ outlives_requirements. as_mut ( ) ,
536+ errors_buffer,
537+ & mut region_naming,
538+ ) ;
539+ }
522540
523541 self . check_member_constraints ( infcx, mir_def_id, errors_buffer) ;
524542
@@ -1375,6 +1393,111 @@ impl<'tcx> RegionInferenceContext<'tcx> {
13751393 outlives_suggestion. add_suggestion ( body, self , infcx, errors_buffer, region_naming) ;
13761394 }
13771395
1396+ /// Checks if Polonius has found any unexpected free region relations.
1397+ ///
1398+ /// In Polonius terms, a "subset error" (or "illegal subset relation error") is the equivalent
1399+ /// of NLL's "checking if any region constraints were too strong": a placeholder origin `'a`
1400+ /// was unexpectedly found to be a subset of another placeholder origin `'b`, and means in NLL
1401+ /// terms that the "longer free region" `'a` outlived the "shorter free region" `'b`.
1402+ ///
1403+ /// More details can be found in this blog post by Niko:
1404+ /// http://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/
1405+ ///
1406+ /// In the canonical example
1407+ ///
1408+ /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
1409+ ///
1410+ /// returning `x` requires `&'a u32 <: &'b u32` and hence we establish (transitively) a
1411+ /// constraint that `'a: 'b`. It is an error that we have no evidence that this
1412+ /// constraint holds.
1413+ ///
1414+ /// If `propagated_outlives_requirements` is `Some`, then we will
1415+ /// push unsatisfied obligations into there. Otherwise, we'll
1416+ /// report them as errors.
1417+ fn check_polonius_subset_errors (
1418+ & self ,
1419+ infcx : & InferCtxt < ' _ , ' tcx > ,
1420+ body : & Body < ' tcx > ,
1421+ local_names : & IndexVec < Local , Option < Symbol > > ,
1422+ upvars : & [ Upvar ] ,
1423+ mir_def_id : DefId ,
1424+ mut propagated_outlives_requirements : Option < & mut Vec < ClosureOutlivesRequirement < ' tcx > > > ,
1425+ errors_buffer : & mut Vec < Diagnostic > ,
1426+ region_naming : & mut RegionErrorNamingCtx ,
1427+ polonius_output : Rc < PoloniusOutput > ,
1428+ ) {
1429+ debug ! ( "check_polonius_subset_errors: {} subset_errors" , polonius_output. subset_errors. len( ) ) ;
1430+
1431+ let mut outlives_suggestion = OutlivesSuggestionBuilder :: new ( mir_def_id, local_names) ;
1432+
1433+ // Similarly to `check_universal_regions`: a free region relation, which was not explicitly
1434+ // declared ("known") was found by Polonius, so emit an error, or propagate the
1435+ // requirements for our caller into the `propagated_outlives_requirements` vector.
1436+ //
1437+ // Polonius doesn't model regions ("origins") as CFG-subsets or durations, but the
1438+ // `longer_fr` and `shorter_fr` terminology will still be used here, for consistency with
1439+ // the rest of the NLL infrastructure. The "subset origin" is the "longer free region",
1440+ // and the "superset origin" is the outlived "shorter free region".
1441+ //
1442+ // Note: Polonius will produce a subset error at every point where the unexpected
1443+ // `longer_fr`'s "placeholder loan" is contained in the `shorter_fr`. This can be helpful
1444+ // for diagnostics in the future, e.g. to point more precisely at the key locations
1445+ // requiring this constraint to hold. However, the error and diagnostics code downstream
1446+ // expects that these errors are not duplicated (and that they are in a certain order).
1447+ // Otherwise, diagnostics messages such as the ones giving names like `'1` to elided or
1448+ // anonymous lifetimes for example, could give these names differently, while others like
1449+ // the outlives suggestions or the debug output from `#[rustc_regions]` would be
1450+ // duplicated. The polonius subset errors are deduplicated here, while keeping the
1451+ // CFG-location ordering.
1452+ let mut subset_errors: Vec < _ > = polonius_output
1453+ . subset_errors
1454+ . iter ( )
1455+ . flat_map ( |( _location, subset_errors) | subset_errors. iter ( ) )
1456+ . collect ( ) ;
1457+ subset_errors. sort ( ) ;
1458+ subset_errors. dedup ( ) ;
1459+
1460+ for ( longer_fr, shorter_fr) in subset_errors. into_iter ( ) {
1461+ debug ! ( "check_polonius_subset_errors: subset_error longer_fr={:?},\
1462+ shorter_fr={:?}", longer_fr, shorter_fr) ;
1463+
1464+ self . report_or_propagate_universal_region_error (
1465+ * longer_fr,
1466+ * shorter_fr,
1467+ infcx,
1468+ body,
1469+ local_names,
1470+ upvars,
1471+ mir_def_id,
1472+ & mut propagated_outlives_requirements,
1473+ & mut outlives_suggestion,
1474+ errors_buffer,
1475+ region_naming,
1476+ ) ;
1477+ }
1478+
1479+ // Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has
1480+ // a more complete picture on how to separate this responsibility.
1481+ for ( fr, fr_definition) in self . definitions . iter_enumerated ( ) {
1482+ match fr_definition. origin {
1483+ NLLRegionVariableOrigin :: FreeRegion => {
1484+ // handled by polonius above
1485+ }
1486+
1487+ NLLRegionVariableOrigin :: Placeholder ( placeholder) => {
1488+ self . check_bound_universal_region ( infcx, body, mir_def_id, fr, placeholder) ;
1489+ }
1490+
1491+ NLLRegionVariableOrigin :: Existential { .. } => {
1492+ // nothing to check here
1493+ }
1494+ }
1495+ }
1496+
1497+ // Emit outlives suggestions
1498+ outlives_suggestion. add_suggestion ( body, self , infcx, errors_buffer, region_naming) ;
1499+ }
1500+
13781501 /// Checks the final value for the free region `fr` to see if it
13791502 /// grew too large. In particular, examine what `end(X)` points
13801503 /// wound up in `fr`'s final value; for each `end(X)` where `X !=
@@ -1474,8 +1597,37 @@ impl<'tcx> RegionInferenceContext<'tcx> {
14741597 return None ;
14751598 }
14761599
1600+ self . report_or_propagate_universal_region_error (
1601+ longer_fr,
1602+ shorter_fr,
1603+ infcx,
1604+ body,
1605+ local_names,
1606+ upvars,
1607+ mir_def_id,
1608+ propagated_outlives_requirements,
1609+ outlives_suggestion,
1610+ errors_buffer,
1611+ region_naming,
1612+ )
1613+ }
1614+
1615+ fn report_or_propagate_universal_region_error (
1616+ & self ,
1617+ longer_fr : RegionVid ,
1618+ shorter_fr : RegionVid ,
1619+ infcx : & InferCtxt < ' _ , ' tcx > ,
1620+ body : & Body < ' tcx > ,
1621+ local_names : & IndexVec < Local , Option < Symbol > > ,
1622+ upvars : & [ Upvar ] ,
1623+ mir_def_id : DefId ,
1624+ propagated_outlives_requirements : & mut Option < & mut Vec < ClosureOutlivesRequirement < ' tcx > > > ,
1625+ outlives_suggestion : & mut OutlivesSuggestionBuilder < ' _ > ,
1626+ errors_buffer : & mut Vec < Diagnostic > ,
1627+ region_naming : & mut RegionErrorNamingCtx ,
1628+ ) -> Option < ErrorReported > {
14771629 debug ! (
1478- "check_universal_region_relation : fr={:?} does not outlive shorter_fr={:?}" ,
1630+ "report_or_propagate_universal_region_error : fr={:?} does not outlive shorter_fr={:?}" ,
14791631 longer_fr, shorter_fr,
14801632 ) ;
14811633
@@ -1484,9 +1636,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
14841636 // We'll call it `fr-` -- it's ever so slightly smaller than
14851637 // `longer_fr`.
14861638
1487- if let Some ( fr_minus) = self . universal_region_relations . non_local_lower_bound ( longer_fr )
1488- {
1489- debug ! ( "check_universal_region : fr_minus={:?}" , fr_minus) ;
1639+ if let Some ( fr_minus) =
1640+ self . universal_region_relations . non_local_lower_bound ( longer_fr ) {
1641+ debug ! ( "report_or_propagate_universal_region_error : fr_minus={:?}" , fr_minus) ;
14901642
14911643 let blame_span_category =
14921644 self . find_outlives_blame_span ( body, longer_fr,
@@ -1497,7 +1649,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
14971649 // so slightly larger than `shorter_fr`.
14981650 let shorter_fr_plus =
14991651 self . universal_region_relations . non_local_upper_bounds ( & shorter_fr) ;
1500- debug ! ( "check_universal_region: shorter_fr_plus={:?}" , shorter_fr_plus) ;
1652+ debug ! (
1653+ "report_or_propagate_universal_region_error: shorter_fr_plus={:?}" , shorter_fr_plus
1654+ ) ;
15011655 for & & fr in & shorter_fr_plus {
15021656 // Push the constraint `fr-: shorter_fr+`
15031657 propagated_outlives_requirements. push ( ClosureOutlivesRequirement {
0 commit comments