Skip to content

Commit b0eb5eb

Browse files
committed
Use structurally_normalize instead of manual normalizes-to goals
1 parent b605c65 commit b0eb5eb

20 files changed

+237
-108
lines changed

compiler/rustc_next_trait_solver/src/solve/mod.rs

+19-23
Original file line numberDiff line numberDiff line change
@@ -277,23 +277,7 @@ where
277277
param_env: I::ParamEnv,
278278
ty: I::Ty,
279279
) -> Result<I::Ty, NoSolution> {
280-
if let ty::Alias(..) = ty.kind() {
281-
let normalized_ty = self.next_ty_infer();
282-
let alias_relate_goal = Goal::new(
283-
self.cx(),
284-
param_env,
285-
ty::PredicateKind::AliasRelate(
286-
ty.into(),
287-
normalized_ty.into(),
288-
ty::AliasRelationDirection::Equate,
289-
),
290-
);
291-
self.add_goal(GoalSource::Misc, alias_relate_goal);
292-
self.try_evaluate_added_goals()?;
293-
Ok(self.resolve_vars_if_possible(normalized_ty))
294-
} else {
295-
Ok(ty)
296-
}
280+
self.structurally_normalize_term(param_env, ty.into()).map(|term| term.expect_ty())
297281
}
298282

299283
/// Normalize a const for when it is structurally matched on, or more likely
@@ -308,22 +292,34 @@ where
308292
param_env: I::ParamEnv,
309293
ct: I::Const,
310294
) -> Result<I::Const, NoSolution> {
311-
if let ty::ConstKind::Unevaluated(..) = ct.kind() {
312-
let normalized_ct = self.next_const_infer();
295+
self.structurally_normalize_term(param_env, ct.into()).map(|term| term.expect_const())
296+
}
297+
298+
/// Normalize a term for when it is structurally matched on.
299+
///
300+
/// This function is necessary in nearly all cases before matching on a ty/const.
301+
/// Not doing so is likely to be incomplete and therefore unsound during coherence.
302+
fn structurally_normalize_term(
303+
&mut self,
304+
param_env: I::ParamEnv,
305+
term: I::Term,
306+
) -> Result<I::Term, NoSolution> {
307+
if let Some(_) = term.to_alias_term() {
308+
let normalized_term = self.next_term_infer_of_kind(term);
313309
let alias_relate_goal = Goal::new(
314310
self.cx(),
315311
param_env,
316312
ty::PredicateKind::AliasRelate(
317-
ct.into(),
318-
normalized_ct.into(),
313+
term,
314+
normalized_term,
319315
ty::AliasRelationDirection::Equate,
320316
),
321317
);
322318
self.add_goal(GoalSource::Misc, alias_relate_goal);
323319
self.try_evaluate_added_goals()?;
324-
Ok(self.resolve_vars_if_possible(normalized_ct))
320+
Ok(self.resolve_vars_if_possible(normalized_term))
325321
} else {
326-
Ok(ct)
322+
Ok(term)
327323
}
328324
}
329325

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

+8-13
Original file line numberDiff line numberDiff line change
@@ -1338,20 +1338,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13381338
let derive_better_type_error =
13391339
|alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| {
13401340
let ocx = ObligationCtxt::new(self);
1341-
let normalized_term = match expected_term.unpack() {
1342-
ty::TermKind::Ty(_) => self.next_ty_var(DUMMY_SP).into(),
1343-
ty::TermKind::Const(_) => self.next_const_var(DUMMY_SP).into(),
1344-
};
1345-
ocx.register_obligation(Obligation::new(
1346-
self.tcx,
1347-
ObligationCause::dummy(),
1341+
1342+
let Ok(normalized_term) = ocx.structurally_normalize_term(
1343+
&ObligationCause::dummy(),
13481344
obligation.param_env,
1349-
ty::PredicateKind::NormalizesTo(ty::NormalizesTo {
1350-
alias: alias_term,
1351-
term: normalized_term,
1352-
}),
1353-
));
1354-
let _ = ocx.select_where_possible();
1345+
alias_term.to_term(self.tcx),
1346+
) else {
1347+
return None;
1348+
};
1349+
13551350
if let Err(terr) = ocx.eq(
13561351
&ObligationCause::dummy(),
13571352
obligation.param_env,

compiler/rustc_trait_selection/src/traits/engine.rs

+11
Original file line numberDiff line numberDiff line change
@@ -340,4 +340,15 @@ where
340340
.at(cause, param_env)
341341
.structurally_normalize_const(value, &mut **self.engine.borrow_mut())
342342
}
343+
344+
pub fn structurally_normalize_term(
345+
&self,
346+
cause: &ObligationCause<'tcx>,
347+
param_env: ty::ParamEnv<'tcx>,
348+
value: ty::Term<'tcx>,
349+
) -> Result<ty::Term<'tcx>, Vec<E>> {
350+
self.infcx
351+
.at(cause, param_env)
352+
.structurally_normalize_term(value, &mut **self.engine.borrow_mut())
353+
}
343354
}

compiler/rustc_trait_selection/src/traits/structural_normalize.rs

+24-47
Original file line numberDiff line numberDiff line change
@@ -12,54 +12,37 @@ impl<'tcx> At<'_, 'tcx> {
1212
ty: Ty<'tcx>,
1313
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
1414
) -> Result<Ty<'tcx>, Vec<E>> {
15-
assert!(!ty.is_ty_var(), "should have resolved vars before calling");
16-
17-
if self.infcx.next_trait_solver() {
18-
let ty::Alias(..) = *ty.kind() else {
19-
return Ok(ty);
20-
};
21-
22-
let new_infer_ty = self.infcx.next_ty_var(self.cause.span);
23-
24-
// We simply emit an `alias-eq` goal here, since that will take care of
25-
// normalizing the LHS of the projection until it is a rigid projection
26-
// (or a not-yet-defined opaque in scope).
27-
let obligation = Obligation::new(
28-
self.infcx.tcx,
29-
self.cause.clone(),
30-
self.param_env,
31-
ty::PredicateKind::AliasRelate(
32-
ty.into(),
33-
new_infer_ty.into(),
34-
ty::AliasRelationDirection::Equate,
35-
),
36-
);
37-
38-
fulfill_cx.register_predicate_obligation(self.infcx, obligation);
39-
let errors = fulfill_cx.select_where_possible(self.infcx);
40-
if !errors.is_empty() {
41-
return Err(errors);
42-
}
43-
44-
Ok(self.infcx.resolve_vars_if_possible(new_infer_ty))
45-
} else {
46-
Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx))
47-
}
15+
self.structurally_normalize_term(ty.into(), fulfill_cx).map(|term| term.expect_type())
4816
}
4917

5018
fn structurally_normalize_const<E: 'tcx>(
5119
&self,
5220
ct: ty::Const<'tcx>,
5321
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
5422
) -> Result<ty::Const<'tcx>, Vec<E>> {
55-
assert!(!ct.is_ct_infer(), "should have resolved vars before calling");
23+
if self.infcx.tcx.features().generic_const_exprs() {
24+
return Ok(super::evaluate_const(&self.infcx, ct, self.param_env));
25+
}
26+
27+
self.structurally_normalize_term(ct.into(), fulfill_cx).map(|term| term.expect_const())
28+
}
29+
30+
fn structurally_normalize_term<E: 'tcx>(
31+
&self,
32+
term: ty::Term<'tcx>,
33+
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
34+
) -> Result<ty::Term<'tcx>, Vec<E>> {
35+
assert!(!term.is_infer(), "should have resolved vars before calling");
5636

5737
if self.infcx.next_trait_solver() {
58-
let ty::ConstKind::Unevaluated(..) = ct.kind() else {
59-
return Ok(ct);
60-
};
38+
if let None = term.to_alias_term() {
39+
return Ok(term);
40+
}
6141

62-
let new_infer_ct = self.infcx.next_const_var(self.cause.span);
42+
let new_infer = match term.unpack() {
43+
ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(),
44+
ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(),
45+
};
6346

6447
// We simply emit an `alias-eq` goal here, since that will take care of
6548
// normalizing the LHS of the projection until it is a rigid projection
@@ -68,11 +51,7 @@ impl<'tcx> At<'_, 'tcx> {
6851
self.infcx.tcx,
6952
self.cause.clone(),
7053
self.param_env,
71-
ty::PredicateKind::AliasRelate(
72-
ct.into(),
73-
new_infer_ct.into(),
74-
ty::AliasRelationDirection::Equate,
75-
),
54+
ty::PredicateKind::AliasRelate(term, new_infer, ty::AliasRelationDirection::Equate),
7655
);
7756

7857
fulfill_cx.register_predicate_obligation(self.infcx, obligation);
@@ -81,11 +60,9 @@ impl<'tcx> At<'_, 'tcx> {
8160
return Err(errors);
8261
}
8362

84-
Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
85-
} else if self.infcx.tcx.features().generic_const_exprs() {
86-
Ok(super::evaluate_const(&self.infcx, ct, self.param_env))
63+
Ok(self.infcx.resolve_vars_if_possible(new_infer))
8764
} else {
88-
Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
65+
Ok(self.normalize(term).into_value_registering_obligations(self.infcx, fulfill_cx))
8966
}
9067
}
9168
}

src/tools/tidy/src/ui_tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use ignore::Walk;
1717
const ENTRY_LIMIT: u32 = 901;
1818
// FIXME: The following limits should be reduced eventually.
1919

20-
const ISSUES_ENTRY_LIMIT: u32 = 1667;
20+
const ISSUES_ENTRY_LIMIT: u32 = 1668;
2121

2222
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
2323
"rs", // test source files

tests/ui/async-await/async-closures/is-not-fn.stderr tests/ui/async-await/async-closures/is-not-fn.current.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
error[E0271]: expected `{async closure@is-not-fn.rs:5:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:5:23: 5:25}`
2-
--> $DIR/is-not-fn.rs:5:14
1+
error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
2+
--> $DIR/is-not-fn.rs:8:14
33
|
44
LL | needs_fn(async || {});
55
| -------- ^^^^^^^^^^^ expected `()`, found `async` closure body
66
| |
77
| required by a bound introduced by this call
88
|
99
= note: expected unit type `()`
10-
found `async` closure body `{async closure body@$DIR/is-not-fn.rs:5:23: 5:25}`
10+
found `async` closure body `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
1111
note: required by a bound in `needs_fn`
12-
--> $DIR/is-not-fn.rs:4:25
12+
--> $DIR/is-not-fn.rs:7:25
1313
|
1414
LL | fn needs_fn(x: impl FnOnce()) {}
1515
| ^^^^^^^^ required by this bound in `needs_fn`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
2+
--> $DIR/is-not-fn.rs:8:14
3+
|
4+
LL | needs_fn(async || {});
5+
| -------- ^^^^^^^^^^^ expected `()`, found `async` closure body
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
= note: expected unit type `()`
10+
found `async` closure body `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
11+
note: required by a bound in `needs_fn`
12+
--> $DIR/is-not-fn.rs:7:25
13+
|
14+
LL | fn needs_fn(x: impl FnOnce()) {}
15+
| ^^^^^^^^ required by this bound in `needs_fn`
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0271`.
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
//@ edition:2021
2+
//@ revisions: current next
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@[next] compile-flags: -Znext-solver
25

36
fn main() {
47
fn needs_fn(x: impl FnOnce()) {}
58
needs_fn(async || {});
6-
//~^ ERROR expected `{async closure@is-not-fn.rs:5:14}` to be a closure that returns `()`
9+
//~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`
710
}

tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0407]: method `line_stream` is not a member of trait `X`
2-
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:5
2+
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:5
33
|
44
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X`
66

77
error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter
8-
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:22:21
8+
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:21
99
|
1010
LL | type LineStream<'a, Repr>
1111
| -- ----
@@ -18,7 +18,7 @@ LL | type LineStream<'c, 'd> = impl Stream;
1818
| found 0 type parameters
1919

2020
error[E0277]: `()` is not a future
21-
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:43
21+
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:43
2222
|
2323
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
2424
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0407]: method `line_stream` is not a member of trait `X`
2+
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:5
3+
|
4+
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X`
6+
7+
error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter
8+
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:21
9+
|
10+
LL | type LineStream<'a, Repr>
11+
| -- ----
12+
| |
13+
| expected 1 type parameter
14+
...
15+
LL | type LineStream<'c, 'd> = impl Stream;
16+
| ^^ ^^
17+
| |
18+
| found 0 type parameters
19+
20+
error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
21+
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:43
22+
|
23+
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
25+
26+
error: aborting due to 3 previous errors
27+
28+
Some errors have detailed explanations: E0049, E0271, E0407.
29+
For more information about an error, try `rustc --explain E0049`.

tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
14
// test for ICE #112823
25
// Unexpected parameter Type(Repr) when substituting in region
36

@@ -23,8 +26,9 @@ impl X for Y {
2326
//~^ ERROR type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter
2427
type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>>;
2528
fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
26-
//~^ ERROR `()` is not a future
27-
//~^^ method `line_stream` is not a member of trait `X`
29+
//[current]~^ ERROR `()` is not a future
30+
//[next]~^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
31+
//~^^^ method `line_stream` is not a member of trait `X`
2832
}
2933

3034
pub fn main() {}

tests/ui/issues/issue-33941.stderr tests/ui/issues/issue-33941.current.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
2-
--> $DIR/issue-33941.rs:6:36
2+
--> $DIR/issue-33941.rs:9:36
33
|
44
LL | for _ in HashMap::new().iter().cloned() {}
55
| ^^^^^^ expected `&_`, found `(&_, &_)`
66
|
77
= note: expected reference `&_`
88
found tuple `(&_, &_)`
99
note: the method call chain might not have had the expected associated types
10-
--> $DIR/issue-33941.rs:6:29
10+
--> $DIR/issue-33941.rs:9:29
1111
|
1212
LL | for _ in HashMap::new().iter().cloned() {}
1313
| -------------- ^^^^^^ `Iterator::Item` is `(&_, &_)` here
@@ -17,7 +17,7 @@ note: required by a bound in `cloned`
1717
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
1818

1919
error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
20-
--> $DIR/issue-33941.rs:6:14
20+
--> $DIR/issue-33941.rs:9:14
2121
|
2222
LL | for _ in HashMap::new().iter().cloned() {}
2323
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `(&_, &_)`
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
2+
--> $DIR/issue-33941.rs:9:36
3+
|
4+
LL | for _ in HashMap::new().iter().cloned() {}
5+
| ^^^^^^ expected `&_`, found `(&_, &_)`
6+
|
7+
= note: expected reference `&_`
8+
found tuple `(&_, &_)`
9+
note: required by a bound in `cloned`
10+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
11+
12+
error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
13+
--> $DIR/issue-33941.rs:9:14
14+
|
15+
LL | for _ in HashMap::new().iter().cloned() {}
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `(&_, &_)`
17+
|
18+
= note: expected reference `&_`
19+
found tuple `(&_, &_)`
20+
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `Iterator`
21+
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `IntoIterator`
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)