Skip to content

Commit 283c81f

Browse files
committed
wf: emit projection goal for aliases
To check that their normalization succeeds in the current environment. This eagerly detects ambiguous and diverging aliases.
1 parent 0e517d3 commit 283c81f

File tree

33 files changed

+340
-100
lines changed

33 files changed

+340
-100
lines changed

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ fn compare_method_predicate_entailment<'tcx>(
393393
for obligation in obligations {
394394
debug!(?obligation);
395395
match obligation.predicate.kind().skip_binder() {
396-
// We need to register Projection oblgiations too, because we may end up with
396+
// We need to register Projection obligations too, because we may end up with
397397
// an implied `X::Item: 'a`, which gets desugared into `X::Item = ?0`, `?0: 'a`.
398398
// If we only register the region outlives obligation, this leads to an unconstrained var.
399399
// See `implied_bounds_entailment_alias_var.rs` test.

compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs

-2
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,6 @@ fn check_predicates<'tcx>(
381381
let obligations =
382382
wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, term, span)
383383
.unwrap();
384-
385-
assert!(!obligations.has_infer());
386384
impl2_predicates
387385
.extend(traits::elaborate(tcx, obligations).map(|obligation| obligation.predicate))
388386
}

compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3939
self.type_matches_expected_vid(expected_vid, data.self_ty())
4040
}
4141
ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
42-
self.type_matches_expected_vid(expected_vid, data.projection_term.self_ty())
42+
match data.projection_term.kind(self.tcx) {
43+
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
44+
self.type_matches_expected_vid(expected_vid, data.projection_term.self_ty())
45+
}
46+
ty::AliasTermKind::InherentTy
47+
| ty::AliasTermKind::OpaqueTy
48+
| ty::AliasTermKind::FreeTy
49+
| ty::AliasTermKind::UnevaluatedConst => false,
50+
}
4351
}
4452
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
4553
| ty::PredicateKind::Subtype(..)

compiler/rustc_trait_selection/src/traits/wf.rs

+28-9
Original file line numberDiff line numberDiff line change
@@ -509,8 +509,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
509509
let obligations = self.nominal_obligations(data.def_id, args);
510510
self.out.extend(obligations);
511511
}
512-
513-
data.args.visit_with(self);
514512
}
515513

516514
fn add_wf_preds_for_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
@@ -771,13 +769,34 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
771769
// Simple cases that are WF if their type args are WF.
772770
}
773771

774-
ty::Alias(ty::Projection | ty::Opaque | ty::Free, data) => {
775-
let obligations = self.nominal_obligations(data.def_id, data.args);
776-
self.out.extend(obligations);
777-
}
778-
ty::Alias(ty::Inherent, data) => {
779-
self.add_wf_preds_for_inherent_projection(data);
780-
return; // Subtree handled by compute_inherent_projection.
772+
ty::Alias(kind, data) => {
773+
let code = ObligationCauseCode::Misc;
774+
let cause = self.cause(code);
775+
let inf = self.infcx.next_ty_var(rustc_span::DUMMY_SP);
776+
let projection_goal_supported =
777+
matches!(kind, ty::Projection) || self.infcx.next_trait_solver();
778+
if projection_goal_supported && !data.has_escaping_bound_vars() {
779+
let obligation: traits::PredicateObligation<'tcx> =
780+
traits::Obligation::with_depth(
781+
self.tcx(),
782+
cause,
783+
self.recursion_depth,
784+
self.param_env,
785+
ty::ProjectionPredicate {
786+
projection_term: data.into(),
787+
term: inf.into(),
788+
},
789+
);
790+
self.out.push(obligation);
791+
}
792+
793+
match kind {
794+
ty::Projection | ty::Opaque | ty::Free => {
795+
let obligations = self.nominal_obligations(data.def_id, data.args);
796+
self.out.extend(obligations);
797+
}
798+
ty::Inherent => self.add_wf_preds_for_inherent_projection(data),
799+
}
781800
}
782801

783802
ty::Adt(def, args) => {

tests/ui/associated-inherent-types/normalization-overflow.stderr renamed to tests/ui/associated-inherent-types/normalization-overflow.current.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: overflow evaluating associated type `T::This`
2-
--> $DIR/normalization-overflow.rs:9:17
2+
--> $DIR/normalization-overflow.rs:12:17
33
|
44
LL | type This = Self::This;
55
| ^^^^^^^^^^
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0271]: type mismatch resolving `T::This normalizes-to _`
2+
--> $DIR/normalization-overflow.rs:12:17
3+
|
4+
LL | type This = Self::This;
5+
| ^^^^^^^^^^ types differ
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0271`.
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//@ revisions: current next
2+
//@[next] compile-flags: -Znext-solver
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
14
#![feature(inherent_associated_types)]
25
#![allow(incomplete_features)]
36

@@ -6,7 +9,9 @@
69
struct T;
710

811
impl T {
9-
type This = Self::This; //~ ERROR overflow evaluating associated type `T::This`
12+
type This = Self::This;
13+
//[current]~^ ERROR overflow evaluating associated type `T::This`
14+
//[next]~^^ ERROR type mismatch resolving `T::This normalizes-to _`
1015
}
1116

1217
fn main() {}

tests/ui/auto-traits/assoc-ty.next.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,15 @@ LL | let _: <() as Trait>::Output = ();
3535
|
3636
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
3737

38-
error: aborting due to 4 previous errors
38+
error[E0271]: type mismatch resolving `<() as Trait>::Output normalizes-to _`
39+
--> $DIR/assoc-ty.rs:15:12
40+
|
41+
LL | let _: <() as Trait>::Output = ();
42+
| ^^^^^^^^^^^^^^^^^^^^^ types differ
43+
|
44+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
45+
46+
error: aborting due to 5 previous errors
3947

4048
Some errors have detailed explanations: E0271, E0380, E0658.
4149
For more information about an error, try `rustc --explain E0271`.

tests/ui/auto-traits/assoc-ty.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ fn main() {
1616
//[current]~^ ERROR mismatched types
1717
//[next]~^^ ERROR type mismatch resolving `<() as Trait>::Output normalizes-to _`
1818
//[next]~| ERROR type mismatch resolving `<() as Trait>::Output normalizes-to _`
19+
//[next]~| ERROR type mismatch resolving `<() as Trait>::Output normalizes-to _`
1920
}

tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr

-5
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ help: this trait has no implementations, consider adding one
1818
|
1919
LL | trait Foo {}
2020
| ^^^^^^^^^
21-
note: required by a bound in `A`
22-
--> $DIR/alias-bounds-when-not-wf.rs:8:11
23-
|
24-
LL | type A<T: Foo> = T;
25-
| ^^^ required by this bound in `A`
2621

2722
error[E0277]: the trait bound `usize: Foo` is not satisfied
2823
--> $DIR/alias-bounds-when-not-wf.rs:16:10

tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ LL | (build2(x),)
3131
| ------------ returning here with type `(impl Sized,)`
3232

3333
warning: function cannot return without recursing
34-
--> $DIR/recursive-in-exhaustiveness.rs:40:1
34+
--> $DIR/recursive-in-exhaustiveness.rs:41:1
3535
|
3636
LL | fn build3<T>(x: T) -> impl Sized {
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -42,7 +42,7 @@ LL | let (x,) = (build3((x,)),);
4242
= help: a `loop` may express intention better if this is on purpose
4343

4444
error[E0792]: expected generic type parameter, found `(T,)`
45-
--> $DIR/recursive-in-exhaustiveness.rs:49:5
45+
--> $DIR/recursive-in-exhaustiveness.rs:51:5
4646
|
4747
LL | fn build3<T>(x: T) -> impl Sized {
4848
| - this generic parameter must be used with a generic type parameter

tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr

+23-7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
1010
LL | (build2(x),)
1111
| ^^^^^^^^^ types differ
1212

13+
error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
14+
--> $DIR/recursive-in-exhaustiveness.rs:31:6
15+
|
16+
LL | (build2(x),)
17+
| ^^^^^^^^^ types differ
18+
|
19+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
20+
1321
error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
1422
--> $DIR/recursive-in-exhaustiveness.rs:31:5
1523
|
@@ -26,13 +34,21 @@ LL | (build2(x),)
2634
= note: tuples must have a statically known size to be initialized
2735

2836
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
29-
--> $DIR/recursive-in-exhaustiveness.rs:42:17
37+
--> $DIR/recursive-in-exhaustiveness.rs:43:17
3038
|
3139
LL | let (x,) = (build3((x,)),);
3240
| ^^^^^^^^^^^^ types differ
3341

42+
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
43+
--> $DIR/recursive-in-exhaustiveness.rs:43:17
44+
|
45+
LL | let (x,) = (build3((x,)),);
46+
| ^^^^^^^^^^^^ types differ
47+
|
48+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
49+
3450
error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time
35-
--> $DIR/recursive-in-exhaustiveness.rs:42:16
51+
--> $DIR/recursive-in-exhaustiveness.rs:43:16
3652
|
3753
LL | let (x,) = (build3((x,)),);
3854
| ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -41,7 +57,7 @@ LL | let (x,) = (build3((x,)),);
4157
= note: tuples must have a statically known size to be initialized
4258

4359
error[E0308]: mismatched types
44-
--> $DIR/recursive-in-exhaustiveness.rs:42:16
60+
--> $DIR/recursive-in-exhaustiveness.rs:43:16
4561
|
4662
LL | fn build3<T>(x: T) -> impl Sized {
4763
| ---------- the found opaque type
@@ -53,28 +69,28 @@ LL | let (x,) = (build3((x,)),);
5369
found tuple `(impl Sized,)`
5470

5571
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
56-
--> $DIR/recursive-in-exhaustiveness.rs:42:17
72+
--> $DIR/recursive-in-exhaustiveness.rs:43:17
5773
|
5874
LL | let (x,) = (build3((x,)),);
5975
| ^^^^^^^^^^^^ types differ
6076
|
6177
= note: the return type of a function must have a statically known size
6278

6379
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
64-
--> $DIR/recursive-in-exhaustiveness.rs:42:16
80+
--> $DIR/recursive-in-exhaustiveness.rs:43:16
6581
|
6682
LL | let (x,) = (build3((x,)),);
6783
| ^^^^^^^^^^^^^^^ types differ
6884

6985
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
70-
--> $DIR/recursive-in-exhaustiveness.rs:42:17
86+
--> $DIR/recursive-in-exhaustiveness.rs:43:17
7187
|
7288
LL | let (x,) = (build3((x,)),);
7389
| ^^^^^^^^^^^^ types differ
7490
|
7591
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
7692

77-
error: aborting due to 10 previous errors
93+
error: aborting due to 12 previous errors
7894

7995
Some errors have detailed explanations: E0271, E0277, E0284, E0308.
8096
For more information about an error, try `rustc --explain E0271`.

tests/ui/impl-trait/recursive-in-exhaustiveness.rs

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ fn build2<T>(x: T) -> impl Sized {
3232
//[next]~^ ERROR type mismatch resolving
3333
//[next]~| ERROR type mismatch resolving
3434
//[next]~| ERROR the size for values of type
35+
//[next]~| ERROR type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
3536
}
3637

3738
// Opaque<T> = Opaque<(T,)>
@@ -44,6 +45,7 @@ fn build3<T>(x: T) -> impl Sized {
4445
//[next]~| ERROR type mismatch resolving
4546
//[next]~| ERROR type mismatch resolving
4647
//[next]~| ERROR type mismatch resolving
48+
//[next]~| ERROR type mismatch resolving
4749
//[next]~| ERROR the size for values of type
4850
//[next]~| ERROR mismatched types
4951
build3(x)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0275]: overflow normalizing the type alias `X2`
2+
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:11
3+
|
4+
LL | type X1 = X2;
5+
| ^^
6+
|
7+
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
8+
9+
error[E0275]: overflow normalizing the type alias `X3`
10+
--> $DIR/infinite-type-alias-mutual-recursion.rs:14:11
11+
|
12+
LL | type X2 = X3;
13+
| ^^
14+
|
15+
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
16+
17+
error[E0275]: overflow normalizing the type alias `X1`
18+
--> $DIR/infinite-type-alias-mutual-recursion.rs:18:11
19+
|
20+
LL | type X3 = X1;
21+
| ^^
22+
|
23+
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
24+
25+
error: aborting due to 3 previous errors
26+
27+
For more information about this error, try `rustc --explain E0275`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error[E0391]: cycle detected when expanding type alias `X1`
2+
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:11
3+
|
4+
LL | type X1 = X2;
5+
| ^^
6+
|
7+
note: ...which requires expanding type alias `X2`...
8+
--> $DIR/infinite-type-alias-mutual-recursion.rs:14:11
9+
|
10+
LL | type X2 = X3;
11+
| ^^
12+
note: ...which requires expanding type alias `X3`...
13+
--> $DIR/infinite-type-alias-mutual-recursion.rs:18:11
14+
|
15+
LL | type X3 = X1;
16+
| ^^
17+
= note: ...which again requires expanding type alias `X1`, completing the cycle
18+
= note: type aliases cannot be recursive
19+
= help: consider using a struct, enum, or union instead to break the cycle
20+
= help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
21+
note: cycle used when checking that `X1` is well-formed
22+
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:1
23+
|
24+
LL | type X1 = X2;
25+
| ^^^^^^^
26+
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
27+
28+
error: aborting due to 1 previous error
29+
30+
For more information about this error, try `rustc --explain E0391`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0271]: type mismatch resolving `X2 normalizes-to _`
2+
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:11
3+
|
4+
LL | type X1 = X2;
5+
| ^^ types differ
6+
7+
error[E0271]: type mismatch resolving `X3 normalizes-to _`
8+
--> $DIR/infinite-type-alias-mutual-recursion.rs:14:11
9+
|
10+
LL | type X2 = X3;
11+
| ^^ types differ
12+
13+
error[E0271]: type mismatch resolving `X1 normalizes-to _`
14+
--> $DIR/infinite-type-alias-mutual-recursion.rs:18:11
15+
|
16+
LL | type X3 = X1;
17+
| ^^ types differ
18+
19+
error: aborting due to 3 previous errors
20+
21+
For more information about this error, try `rustc --explain E0271`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error[E0391]: cycle detected when expanding type alias `X1`
2+
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:11
3+
|
4+
LL | type X1 = X2;
5+
| ^^
6+
|
7+
note: ...which requires expanding type alias `X2`...
8+
--> $DIR/infinite-type-alias-mutual-recursion.rs:14:11
9+
|
10+
LL | type X2 = X3;
11+
| ^^
12+
note: ...which requires expanding type alias `X3`...
13+
--> $DIR/infinite-type-alias-mutual-recursion.rs:18:11
14+
|
15+
LL | type X3 = X1;
16+
| ^^
17+
= note: ...which again requires expanding type alias `X1`, completing the cycle
18+
= note: type aliases cannot be recursive
19+
= help: consider using a struct, enum, or union instead to break the cycle
20+
= help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
21+
note: cycle used when checking that `X1` is well-formed
22+
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:1
23+
|
24+
LL | type X1 = X2;
25+
| ^^^^^^^
26+
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
27+
28+
error: aborting due to 1 previous error
29+
30+
For more information about this error, try `rustc --explain E0391`.

0 commit comments

Comments
 (0)