Skip to content
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

Check the Self-type of inherent associated constants #58353

Merged
merged 1 commit into from
Feb 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
26 changes: 16 additions & 10 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2236,7 +2236,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
hir_id, def_id, substs, user_self_ty, self.tag(),
);

if !substs.is_noop() {
if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
let canonicalized = self.infcx.canonicalize_user_type_annotation(
&UserType::TypeOf(def_id, UserSubsts {
substs,
Expand Down Expand Up @@ -2431,15 +2431,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let ty = self.to_ty(ast_ty);
debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);

// If the type given by the user has free regions, save it for
// later, since NLL would like to enforce those. Also pass in
// types that involve projections, since those can resolve to
// `'static` bounds (modulo #54940, which hopefully will be
// fixed by the time you see this comment, dear reader,
// although I have my doubts). Also pass in types with inference
// types, because they may be repeated. Other sorts of things
// are already sufficiently enforced with erased regions. =)
if ty.has_free_regions() || ty.has_projections() || ty.has_infer_types() {
if Self::can_contain_user_lifetime_bounds(ty) {
let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty));
debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
Expand All @@ -2448,6 +2440,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
ty
}

// If the type given by the user has free regions, save it for later, since
// NLL would like to enforce those. Also pass in types that involve
// projections, since those can resolve to `'static` bounds (modulo #54940,
// which hopefully will be fixed by the time you see this comment, dear
// reader, although I have my doubts). Also pass in types with inference
// types, because they may be repeated. Other sorts of things are already
// sufficiently enforced with erased regions. =)
fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
where
T: TypeFoldable<'tcx>
{
t.has_free_regions() || t.has_projections() || t.has_infer_types()
}

pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
match self.tables.borrow().node_types().get(id) {
Some(&t) => t,
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ fn main() {

SomeStruct::<_> { t: 22 }; // Nothing interesting given, no annotation.

SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]
SomeStruct::<u32> { t: 22 }; // No lifetime bounds given.

SomeStruct::<&'static u32> { t: &22 }; //~ ERROR [&ReStatic u32]
}
8 changes: 4 additions & 4 deletions src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: user substs: UserSubsts { substs: [u32], user_self_ty: None }
--> $DIR/dump-adt-brace-struct.rs:18:5
error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None }
--> $DIR/dump-adt-brace-struct.rs:20:5
|
LL | SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | SomeStruct::<&'static u32> { t: &22 }; //~ ERROR [&ReStatic u32]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

19 changes: 14 additions & 5 deletions src/test/ui/nll/user-annotations/dump-fn-method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ trait Bazoom<T> {
fn method<U>(&self, arg: T, arg2: U) { }
}

impl<T, U> Bazoom<U> for T {
impl<S, T> Bazoom<T> for S {
}

fn foo<'a, T>(_: T) { }
Expand All @@ -22,20 +22,29 @@ fn main() {
let x = foo;
x(22);

// Here: `u32` is given.
let x = foo::<u32>; //~ ERROR [u32]
// Here: `u32` is given, which doesn't contain any lifetimes, so we don't
// have any annotation.
let x = foo::<u32>;
x(22);

let x = foo::<&'static u32>; //~ ERROR [&ReStatic u32]
x(&22);

// Here: we only want the `T` to be given, the rest should be variables.
//
// (`T` refers to the declaration of `Bazoom`)
let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [^0, u32, ^1]
x(&22, 44, 66);

// Here: all are given
let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
// Here: all are given and definitely contain no lifetimes, so we
// don't have any annotation.
let x = <u8 as Bazoom<u16>>::method::<u32>;
x(&22, 44, 66);

// Here: all are given and we have a lifetime.
let x = <u8 as Bazoom<&'static u16>>::method::<u32>; //~ ERROR [u8, &ReStatic u16, u32]
x(&22, &44, 66);

// Here: we want in particular that *only* the method `U`
// annotation is given, the rest are variables.
//
Expand Down
20 changes: 10 additions & 10 deletions src/test/ui/nll/user-annotations/dump-fn-method.stderr
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
error: user substs: UserSubsts { substs: [u32], user_self_ty: None }
--> $DIR/dump-fn-method.rs:26:13
error: user substs: UserSubsts { substs: [&ReStatic u32], user_self_ty: None }
--> $DIR/dump-fn-method.rs:30:13
|
LL | let x = foo::<u32>; //~ ERROR [u32]
| ^^^^^^^^^^
LL | let x = foo::<&'static u32>; //~ ERROR [&ReStatic u32]
| ^^^^^^^^^^^^^^^^^^^

error: user substs: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None }
--> $DIR/dump-fn-method.rs:32:13
--> $DIR/dump-fn-method.rs:36:13
|
LL | let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [^0, u32, ^1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: user substs: UserSubsts { substs: [u8, u16, u32], user_self_ty: None }
--> $DIR/dump-fn-method.rs:36:13
error: user substs: UserSubsts { substs: [u8, &ReStatic u16, u32], user_self_ty: None }
--> $DIR/dump-fn-method.rs:45:13
|
LL | let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | let x = <u8 as Bazoom<&'static u16>>::method::<u32>; //~ ERROR [u8, &ReStatic u16, u32]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None }
--> $DIR/dump-fn-method.rs:44:5
--> $DIR/dump-fn-method.rs:53:5
|
LL | y.method::<u32>(44, 66); //~ ERROR [^0, ^1, u32]
| ^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/nll/user-annotations/inherent-associated-constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![feature(nll)]

struct A<'a>(&'a ());

impl A<'static> {
const IC: i32 = 10;
}

fn non_wf_associated_const<'a>(x: i32) {
A::<'a>::IC; //~ ERROR lifetime may not live long enough
}

fn wf_associated_const<'a>(x: i32) {
A::<'static>::IC;
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: lifetime may not live long enough
--> $DIR/inherent-associated-constants.rs:10:5
|
LL | fn non_wf_associated_const<'a>(x: i32) {
| -- lifetime `'a` defined here
LL | A::<'a>::IC; //~ ERROR lifetime may not live long enough
| ^^^^^^^^^^^ requires that `'a` must outlive `'static`

error: aborting due to previous error