@@ -49,7 +49,8 @@ fn compute_implied_outlives_bounds<'tcx>(
49
49
let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
50
50
let mut wf_args = vec![ty.into()];
51
51
52
- let mut implied_bounds = vec![];
52
+ let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
53
+ vec![];
53
54
54
55
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
55
56
@@ -65,41 +66,28 @@ fn compute_implied_outlives_bounds<'tcx>(
65
66
// than the ultimate set. (Note: normally there won't be
66
67
// unresolved inference variables here anyway, but there might be
67
68
// during typeck under some circumstances.)
69
+ //
70
+ // FIXME(@lcnr): It's not really "always fine", having fewer implied
71
+ // bounds can be backward incompatible, e.g. #101951 was caused by
72
+ // us not dealing with inference vars in `TypeOutlives` predicates.
68
73
let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
69
74
.unwrap_or_default();
70
75
71
- // N.B., all of these predicates *ought* to be easily proven
72
- // true. In fact, their correctness is (mostly) implied by
73
- // other parts of the program. However, in #42552, we had
74
- // an annoying scenario where:
75
- //
76
- // - Some `T::Foo` gets normalized, resulting in a
77
- // variable `_1` and a `T: Trait<Foo=_1>` constraint
78
- // (not sure why it couldn't immediately get
79
- // solved). This result of `_1` got cached.
80
- // - These obligations were dropped on the floor here,
81
- // rather than being registered.
82
- // - Then later we would get a request to normalize
83
- // `T::Foo` which would result in `_1` being used from
84
- // the cache, but hence without the `T: Trait<Foo=_1>`
85
- // constraint. As a result, `_1` never gets resolved,
86
- // and we get an ICE (in dropck).
87
- //
88
- // Therefore, we register any predicates involving
89
- // inference variables. We restrict ourselves to those
90
- // involving inference variables both for efficiency and
91
- // to avoids duplicate errors that otherwise show up.
76
+ // While these predicates should all be implied by other parts of
77
+ // the program, they are still relevant as they may constrain
78
+ // inference variables, which is necessary to add the correct
79
+ // implied bounds in some cases, mostly when dealing with projections.
92
80
fulfill_cx.register_predicate_obligations(
93
81
infcx,
94
82
obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(),
95
83
);
96
84
97
85
// From the full set of obligations, just filter down to the
98
86
// region relationships.
99
- implied_bounds .extend(obligations.into_iter().flat_map (|obligation| {
87
+ outlives_bounds .extend(obligations.into_iter().filter_map (|obligation| {
100
88
assert!(!obligation.has_escaping_bound_vars());
101
89
match obligation.predicate.kind().no_bound_vars() {
102
- None => vec![] ,
90
+ None => None ,
103
91
Some(pred) => match pred {
104
92
ty::PredicateKind::Trait(..)
105
93
| ty::PredicateKind::Subtype(..)
@@ -109,21 +97,18 @@ fn compute_implied_outlives_bounds<'tcx>(
109
97
| ty::PredicateKind::ObjectSafe(..)
110
98
| ty::PredicateKind::ConstEvaluatable(..)
111
99
| ty::PredicateKind::ConstEquate(..)
112
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![] ,
100
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None ,
113
101
ty::PredicateKind::WellFormed(arg) => {
114
102
wf_args.push(arg);
115
- vec![]
103
+ None
116
104
}
117
105
118
106
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
119
- vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
107
+ Some(ty::OutlivesPredicate(r_a.into(), r_b))
120
108
}
121
109
122
110
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
123
- let ty_a = infcx.resolve_vars_if_possible(ty_a);
124
- let mut components = smallvec![];
125
- push_outlives_components(tcx, ty_a, &mut components);
126
- implied_bounds_from_components(r_b, components)
111
+ Some(ty::OutlivesPredicate(ty_a.into(), r_b))
127
112
}
128
113
},
129
114
}
@@ -133,9 +118,27 @@ fn compute_implied_outlives_bounds<'tcx>(
133
118
// Ensure that those obligations that we had to solve
134
119
// get solved *here*.
135
120
match fulfill_cx.select_all_or_error(infcx).as_slice() {
136
- [] => Ok(implied_bounds ),
137
- _ => Err(NoSolution),
121
+ [] => ( ),
122
+ _ => return Err(NoSolution),
138
123
}
124
+
125
+ // We lazily compute the outlives components as
126
+ // `select_all_or_error` constrains inference variables.
127
+ let implied_bounds = outlives_bounds
128
+ .into_iter()
129
+ .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
130
+ ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
131
+ ty::GenericArgKind::Type(ty_a) => {
132
+ let ty_a = infcx.resolve_vars_if_possible(ty_a);
133
+ let mut components = smallvec![];
134
+ push_outlives_components(tcx, ty_a, &mut components);
135
+ implied_bounds_from_components(r_b, components)
136
+ }
137
+ ty::GenericArgKind::Const(_) => unreachable!(),
138
+ })
139
+ .collect();
140
+
141
+ Ok(implied_bounds)
139
142
}
140
143
141
144
/// When we have an implied bound that `T: 'a`, we can further break
0 commit comments