Skip to content

[NLL] Check user types are well-formed #54942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 12, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -970,15 +970,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
relate_tys::relate_type_and_user_type(
let ty = relate_tys::relate_type_and_user_type(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is okay to have a variable name the same as the module name ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

self.infcx,
a,
v,
b,
locations,
category,
self.borrowck_context.as_mut().map(|x| &mut **x),
)
)?;
self.prove_predicate(
ty::Predicate::WellFormed(ty),
locations,
category,
);
Ok(())
}

fn eq_opaque_type_and_type(
Expand Down
21 changes: 16 additions & 5 deletions src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use borrow_check::nll::constraints::OutlivesConstraint;
use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
use rustc::infer::canonical::{Canonical, CanonicalVarInfos};
use rustc::infer::canonical::{Canonical, CanonicalVarInfos, CanonicalVarValues};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use rustc::mir::ConstraintCategory;
use rustc::traits::query::Fallible;
Expand Down Expand Up @@ -70,7 +70,7 @@ pub(super) fn relate_type_and_user_type<'tcx>(
locations: Locations,
category: ConstraintCategory,
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
) -> Fallible<()> {
) -> Fallible<Ty<'tcx>> {
debug!(
"sub_type_and_user_type(a={:?}, b={:?}, locations={:?})",
a, b, locations
Expand All @@ -85,13 +85,24 @@ pub(super) fn relate_type_and_user_type<'tcx>(
// variance to get the right relationship.
let v1 = ty::Contravariant.xform(v);

TypeRelating::new(
let mut type_relating = TypeRelating::new(
infcx.tcx,
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
v1,
b_variables,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b_variables
Can you explain to me how this magic happens ? b.variables is written as b_variables ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b is destructured just above this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind pointing me to the line please ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 79

).relate(&b_value, &a)?;
Ok(())
);
type_relating.relate(&b_value, &a)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type_relating.relate(&b_value, &a)?;

Can you explain to me what this line does ?

Copy link
Contributor Author

@matthewjasper matthewjasper Oct 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It checks that a and b_value are the same type apart from lifetimes, if they're not it returns an error to the caller. Otherwise, depending on v1, it adds any outlives constraints that are required for a being a subtype of b, or b being a subtype of a or b being the same type as a to the borrowck_context (if it's Some, which it will be during the NLL type check). Finally it works out what any type variables in b should be based on a.

So if b is &mut '_1 &'_2 _, a is &mut '_3 &'_4 i32 and v1is Covariant, the constraints added are'_1: '_3, '_2: '_4and'_4: '_2(the last constraint comes from&mut Tbeing invariant inT), and the type variable is inferred to be i32`.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@matthewjasper Thanks a lot for the explanation. Really appreciate it.


Ok(b.substitute(
infcx.tcx,
&CanonicalVarValues {
var_values: type_relating
.canonical_var_values
.into_iter()
.map(|x| x.expect("unsubstituted canonical variable"))
.collect(),
},
))
}

struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
error: unsatisfied lifetime constraints
--> $DIR/associated-types-subtyping-1.rs:36:13
|
LL | fn method2<'a,'b,T>(x: &'a T, y: &'b T)
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | let _c: <T as Trait<'b>>::Type = a; //~ ERROR E0623
| ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`

error: unsatisfied lifetime constraints
--> $DIR/associated-types-subtyping-1.rs:44:12
|
LL | fn method3<'a,'b,T>(x: &'a T, y: &'b T)
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | let b: <T as Trait<'b>>::Type = make_any();
| ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`

error: aborting due to 2 previous errors

20 changes: 10 additions & 10 deletions src/test/ui/associated-types/associated-types-subtyping-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-compare-mode-nll

#![allow(unused_variables)]

fn make_any<T>() -> T { loop {} }

trait Trait<'a> {
type Type;

Expand All @@ -22,35 +22,35 @@ fn method1<'a,'b,T>(x: &'a T, y: &'b T)
where T : for<'z> Trait<'z>, 'a : 'b
{
// Note that &'static T <: &'a T.
let a: <T as Trait<'a>>::Type = loop { };
let b: <T as Trait<'b>>::Type = loop { };
let a: <T as Trait<'a>>::Type = make_any();
let b: <T as Trait<'b>>::Type = make_any();
let _c: <T as Trait<'a>>::Type = a;
}

fn method2<'a,'b,T>(x: &'a T, y: &'b T)
where T : for<'z> Trait<'z>, 'a : 'b
{
// Note that &'static T <: &'a T.
let a: <T as Trait<'a>>::Type = loop { };
let b: <T as Trait<'b>>::Type = loop { };
let a: <T as Trait<'a>>::Type = make_any();
let b: <T as Trait<'b>>::Type = make_any();
let _c: <T as Trait<'b>>::Type = a; //~ ERROR E0623
}

fn method3<'a,'b,T>(x: &'a T, y: &'b T)
where T : for<'z> Trait<'z>, 'a : 'b
{
// Note that &'static T <: &'a T.
let a: <T as Trait<'a>>::Type = loop { };
let b: <T as Trait<'b>>::Type = loop { };
let a: <T as Trait<'a>>::Type = make_any();
let b: <T as Trait<'b>>::Type = make_any();
let _c: <T as Trait<'a>>::Type = b; //~ ERROR E0623
}

fn method4<'a,'b,T>(x: &'a T, y: &'b T)
where T : for<'z> Trait<'z>, 'a : 'b
{
// Note that &'static T <: &'a T.
let a: <T as Trait<'a>>::Type = loop { };
let b: <T as Trait<'b>>::Type = loop { };
let a: <T as Trait<'a>>::Type = make_any();
let b: <T as Trait<'b>>::Type = make_any();
let _c: <T as Trait<'b>>::Type = b;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: unsatisfied lifetime constraints
--> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:52:13
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`

error: aborting due to previous error

Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-compare-mode-nll

// Test that we are imposing the requirement that every associated
// type of a bound that appears in the where clause on a struct must
// outlive the location in which the type appears, even when the
Expand Down Expand Up @@ -49,7 +47,10 @@ fn with_assoc<'a,'b>() {
// outlive 'a. In this case, that means TheType<'b>::TheAssocType,
// which is &'b (), must outlive 'a.

let _: &'a WithAssoc<TheType<'b>> = loop { }; //~ ERROR reference has a longer lifetime
// FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
// `_x` is changed to `_`
let _x: &'a WithAssoc<TheType<'b>> = loop { };
//~^ ERROR reference has a longer lifetime
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we ope an issue regarding enforcing WF conditions in dead code and put a FIXME here like this:


FIXME(#XXX) -- NLL doesn't enforce WF conditions (or any type annotations) in dead code.

}

fn main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
--> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:52:12
--> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:52:13
|
LL | let _: &'a WithAssoc<TheType<'b>> = loop { }; //~ ERROR reference has a longer lifetime
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime 'a as defined on the function body at 46:15
--> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:46:15
note: the pointer is valid for the lifetime 'a as defined on the function body at 44:15
--> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 46:18
--> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:46:18
note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 44:18
--> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
Expand Down
33 changes: 33 additions & 0 deletions src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
error: unsatisfied lifetime constraints
--> $DIR/regions-free-region-ordering-caller.rs:18:12
|
LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let z: Option<&'b &'a usize> = None;//~ ERROR E0623
| ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`

error: unsatisfied lifetime constraints
--> $DIR/regions-free-region-ordering-caller.rs:23:12
|
LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let y: Paramd<'a> = Paramd { x: a };
LL | let z: Option<&'b Paramd<'a>> = None;//~ ERROR E0623
| ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`

error: unsatisfied lifetime constraints
--> $DIR/regions-free-region-ordering-caller.rs:27:12
|
LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let z: Option<&'a &'b usize> = None;//~ ERROR E0623
| ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`

error: aborting due to 3 previous errors

2 changes: 0 additions & 2 deletions src/test/ui/regions/regions-free-region-ordering-caller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-compare-mode-nll

// Test various ways to construct a pointer with a longer lifetime
// than the thing it points at and ensure that they result in
// errors. See also regions-free-region-ordering-callee.rs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0623]: lifetime mismatch
--> $DIR/regions-free-region-ordering-caller.rs:20:12
--> $DIR/regions-free-region-ordering-caller.rs:18:12
|
LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
| --------- ---------
Expand All @@ -9,7 +9,7 @@ LL | let z: Option<&'b &'a usize> = None;//~ ERROR E0623
| ^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here

error[E0623]: lifetime mismatch
--> $DIR/regions-free-region-ordering-caller.rs:25:12
--> $DIR/regions-free-region-ordering-caller.rs:23:12
|
LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
| --------- ---------
Expand All @@ -20,7 +20,7 @@ LL | let z: Option<&'b Paramd<'a>> = None;//~ ERROR E0623
| ^^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here

error[E0623]: lifetime mismatch
--> $DIR/regions-free-region-ordering-caller.rs:29:12
--> $DIR/regions-free-region-ordering-caller.rs:27:12
|
LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
| --------- --------- these two types are declared with different lifetimes...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@ note: borrowed value must be valid for the lifetime 'a as defined on the functio
LL | fn call1<'a>(x: &'a usize) {
| ^^

error: aborting due to previous error
error[E0597]: `y` does not live long enough
--> $DIR/regions-free-region-ordering-caller1.rs:19:27
|
LL | let z: &'a & usize = &(&y);
| ^^^^ borrowed value does not live long enough
...
LL | }
| - `y` dropped here while still borrowed
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:10...
--> $DIR/regions-free-region-ordering-caller1.rs:15:10
|
LL | fn call1<'a>(x: &'a usize) {
| ^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0716`.
Some errors occurred: E0597, E0716.
For more information about an error, try `rustc --explain E0597`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/regions-implied-bounds-projection-gap-1.rs:26:5
|
LL | wf::<&'x T>();
| ^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `T: 'x`...

error: aborting due to previous error

For more information about this error, try `rustc --explain E0309`.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-compare-mode-nll

// Illustrates the "projection gap": in this test, even though we know
// that `T::Foo: 'x`, that does not tell us that `T: 'x`, because
// there might be other ways for the caller of `func` to show that
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/regions-implied-bounds-projection-gap-1.rs:28:10
--> $DIR/regions-implied-bounds-projection-gap-1.rs:26:10
|
LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo)
| -- help: consider adding an explicit lifetime bound `T: 'x`...
Expand All @@ -8,7 +8,7 @@ LL | wf::<&'x T>();
| ^^^^^
|
note: ...so that the reference type `&'x T` does not outlive the data it points at
--> $DIR/regions-implied-bounds-projection-gap-1.rs:28:10
--> $DIR/regions-implied-bounds-projection-gap-1.rs:26:10
|
LL | wf::<&'x T>();
| ^^^^^
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: unsatisfied lifetime constraints
--> $DIR/regions-outlives-projection-container-wc.rs:46:13
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`

error: aborting due to previous error

Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-compare-mode-nll

// Test that we are imposing the requirement that every associated
// type of a bound that appears in the where clause on a struct must
// outlive the location in which the type appears, even when the
Expand Down Expand Up @@ -43,7 +41,9 @@ fn with_assoc<'a,'b>() {
// outlive 'a. In this case, that means TheType<'b>::TheAssocType,
// which is &'b (), must outlive 'a.

let _: &'a WithAssoc<TheType<'b>> = loop { };
// FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
// `_x` is changed to `_`
let _x: &'a WithAssoc<TheType<'b>> = loop { };
//~^ ERROR reference has a longer lifetime
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
--> $DIR/regions-outlives-projection-container-wc.rs:46:12
--> $DIR/regions-outlives-projection-container-wc.rs:46:13
|
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | let _x: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime 'a as defined on the function body at 40:15
--> $DIR/regions-outlives-projection-container-wc.rs:40:15
note: the pointer is valid for the lifetime 'a as defined on the function body at 38:15
--> $DIR/regions-outlives-projection-container-wc.rs:38:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 40:18
--> $DIR/regions-outlives-projection-container-wc.rs:40:18
note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 38:18
--> $DIR/regions-outlives-projection-container-wc.rs:38:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
Expand Down
Loading