Skip to content

Commit aac2f84

Browse files
aliemjaylcnr
authored andcommitted
wf-check type annotations before normalization
1 parent 8d4693c commit aac2f84

File tree

3 files changed

+62
-29
lines changed

3 files changed

+62
-29
lines changed

compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs

+32-22
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,16 @@ fn relate_mir_and_user_ty<'tcx>(
6363
user_ty: Ty<'tcx>,
6464
) -> Result<(), NoSolution> {
6565
let cause = ObligationCause::dummy_with_span(span);
66+
ocx.register_obligation(Obligation::new(
67+
ocx.infcx.tcx,
68+
cause.clone(),
69+
param_env,
70+
ty::ClauseKind::WellFormed(user_ty.into()),
71+
));
72+
6673
let user_ty = ocx.normalize(&cause, param_env, user_ty);
6774
ocx.eq(&cause, param_env, mir_ty, user_ty)?;
6875

69-
// FIXME(#104764): We should check well-formedness before normalization.
70-
let predicate =
71-
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(user_ty.into())));
72-
ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
7376
Ok(())
7477
}
7578

@@ -113,31 +116,38 @@ fn relate_mir_and_user_args<'tcx>(
113116
ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
114117
}
115118

119+
// Now prove the well-formedness of `def_id` with `substs`.
120+
// Note for some items, proving the WF of `ty` is not sufficient because the
121+
// well-formedness of an item may depend on the WF of gneneric args not present in the
122+
// item's type. Currently this is true for associated consts, e.g.:
123+
// ```rust
124+
// impl<T> MyTy<T> {
125+
// const CONST: () = { /* arbitrary code that depends on T being WF */ };
126+
// }
127+
// ```
128+
for arg in args {
129+
ocx.register_obligation(Obligation::new(
130+
tcx,
131+
cause.clone(),
132+
param_env,
133+
ty::ClauseKind::WellFormed(arg),
134+
));
135+
}
136+
116137
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
138+
ocx.register_obligation(Obligation::new(
139+
tcx,
140+
cause.clone(),
141+
param_env,
142+
ty::ClauseKind::WellFormed(self_ty.into()),
143+
));
144+
117145
let self_ty = ocx.normalize(&cause, param_env, self_ty);
118146
let impl_self_ty = tcx.type_of(impl_def_id).instantiate(tcx, args);
119147
let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
120148

121149
ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
122-
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
123-
impl_self_ty.into(),
124-
)));
125-
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
126150
}
127151

128-
// In addition to proving the predicates, we have to
129-
// prove that `ty` is well-formed -- this is because
130-
// the WF of `ty` is predicated on the args being
131-
// well-formed, and we haven't proven *that*. We don't
132-
// want to prove the WF of types from `args` directly because they
133-
// haven't been normalized.
134-
//
135-
// FIXME(nmatsakis): Well, perhaps we should normalize
136-
// them? This would only be relevant if some input
137-
// type were ill-formed but did not appear in `ty`,
138-
// which...could happen with normalization...
139-
let predicate =
140-
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into())));
141-
ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
142152
Ok(())
143153
}

tests/ui/wf/wf-associated-const.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
// check that associated consts can assume the impl header is well-formed.
22

3-
// FIXME(aliemjay): we should check the impl header is WF at the use site
4-
// but we currently don't in some cases. This is *unsound*.
5-
63
trait Foo<'a, 'b, T>: Sized {
74
const EVIL: fn(u: &'b u32) -> &'a u32;
85
}
@@ -27,11 +24,13 @@ impl<'a, 'b> Evil<'a, 'b> {
2724
// *check* that it holds at the use site.
2825

2926
fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
30-
<()>::EVIL(b) // FIXME: should be an error
27+
<()>::EVIL(b)
28+
//~^ ERROR lifetime may not live long enough
3129
}
3230

3331
fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
34-
<IndirectEvil>::EVIL(b) // FIXME: should be an error
32+
<IndirectEvil>::EVIL(b)
33+
//~^ ERROR lifetime may not live long enough
3534
}
3635

3736
fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {

tests/ui/wf/wf-associated-const.stderr

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
error: lifetime may not live long enough
2-
--> $DIR/wf-associated-const.rs:38:5
2+
--> $DIR/wf-associated-const.rs:27:5
3+
|
4+
LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
5+
| -- -- lifetime `'b` defined here
6+
| |
7+
| lifetime `'a` defined here
8+
LL | <()>::EVIL(b)
9+
| ^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
10+
|
11+
= help: consider adding the following bound: `'b: 'a`
12+
13+
error: lifetime may not live long enough
14+
--> $DIR/wf-associated-const.rs:32:5
15+
|
16+
LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
17+
| -- -- lifetime `'b` defined here
18+
| |
19+
| lifetime `'a` defined here
20+
LL | <IndirectEvil>::EVIL(b)
21+
| ^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
22+
|
23+
= help: consider adding the following bound: `'b: 'a`
24+
25+
error: lifetime may not live long enough
26+
--> $DIR/wf-associated-const.rs:37:5
327
|
428
LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
529
| -- -- lifetime `'b` defined here
@@ -10,5 +34,5 @@ LL | <Evil>::INHERENT_EVIL(b)
1034
|
1135
= help: consider adding the following bound: `'b: 'a`
1236

13-
error: aborting due to previous error
37+
error: aborting due to 3 previous errors
1438

0 commit comments

Comments
 (0)