Skip to content

Commit feb139f

Browse files
committed
Check lifetimes on existential types
1 parent 240fcdf commit feb139f

11 files changed

+218
-39
lines changed

src/librustc/infer/anon_types/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
653653
let tcx = self.infcx.tcx;
654654
value.fold_with(&mut BottomUpFolder {
655655
tcx,
656+
reg_op: |reg| reg,
656657
fldop: |ty| {
657658
if let ty::TyAnon(def_id, substs) = ty.sty {
658659
// Check that this is `impl Trait` type is

src/librustc/ty/fold.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,22 +200,30 @@ pub trait TypeVisitor<'tcx> : Sized {
200200
///////////////////////////////////////////////////////////////////////////
201201
// Some sample folders
202202

203-
pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F>
204-
where F: FnMut(Ty<'tcx>) -> Ty<'tcx>
203+
pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G>
204+
where F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
205+
G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
205206
{
206207
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
207208
pub fldop: F,
209+
pub reg_op: G,
208210
}
209211

210-
impl<'a, 'gcx, 'tcx, F> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F>
212+
impl<'a, 'gcx, 'tcx, F, G> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G>
211213
where F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
214+
G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
212215
{
213216
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
214217

215218
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
216219
let t1 = ty.super_fold_with(self);
217220
(self.fldop)(t1)
218221
}
222+
223+
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
224+
let r = r.super_fold_with(self);
225+
(self.reg_op)(r)
226+
}
219227
}
220228

221229
///////////////////////////////////////////////////////////////////////////

src/librustc_typeck/check/wfcheck.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,10 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
575575
let anon_node_id = tcx.hir.as_local_node_id(def_id).unwrap();
576576
if may_define_existential_type(tcx, fn_def_id, anon_node_id) {
577577
trace!("check_existential_types may define. Generics: {:#?}", generics);
578+
let mut seen: FxHashMap<_, Vec<_>> = FxHashMap();
578579
for (subst, param) in substs.iter().zip(&generics.params) {
579-
if let ty::subst::UnpackedKind::Type(ty) = subst.unpack() {
580-
match ty.sty {
580+
match subst.unpack() {
581+
ty::subst::UnpackedKind::Type(ty) => match ty.sty {
581582
ty::TyParam(..) => {},
582583
// prevent `fn foo() -> Foo<u32>` from being defining
583584
_ => {
@@ -597,11 +598,47 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
597598
),
598599
)
599600
.emit();
600-
return tcx.types.err;
601601
},
602-
} // match ty
603-
} // if let Type = subst
602+
}, // match ty
603+
ty::subst::UnpackedKind::Lifetime(region) => {
604+
let param_span = tcx.def_span(param.def_id);
605+
if let ty::ReStatic = region {
606+
tcx
607+
.sess
608+
.struct_span_err(
609+
span,
610+
"non-defining existential type use \
611+
in defining scope",
612+
)
613+
.span_label(
614+
param_span,
615+
"cannot use static lifetime, use a bound lifetime \
616+
instead or remove the lifetime parameter from the \
617+
existential type",
618+
)
619+
.emit();
620+
} else {
621+
seen.entry(region).or_default().push(param_span);
622+
}
623+
},
624+
} // match subst
604625
} // for (subst, param)
626+
for (_, spans) in seen {
627+
if spans.len() > 1 {
628+
tcx
629+
.sess
630+
.struct_span_err(
631+
span,
632+
"non-defining existential type use \
633+
in defining scope",
634+
).
635+
span_note(
636+
spans,
637+
"lifetime used multiple times",
638+
)
639+
.emit();
640+
}
641+
}
605642
} // if may_define_existential_type
606643

607644
// now register the bounds on the parameters of the existential type
@@ -631,6 +668,7 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
631668
} // if let TyAnon
632669
ty
633670
},
671+
reg_op: |reg| reg,
634672
});
635673
substituted_predicates
636674
}

src/librustc_typeck/check/writeback.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -389,16 +389,17 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
389389
for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
390390
let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
391391
let instantiated_ty = self.resolve(&anon_defn.concrete_ty, &node_id);
392-
let mut definition_ty = self.fcx.infer_anon_definition_from_instantiation(
393-
def_id,
394-
anon_defn,
395-
instantiated_ty,
396-
);
397392

398393
let generics = self.tcx().generics_of(def_id);
399394

400-
// named existential type, not an impl trait
401-
if generics.parent.is_none() {
395+
let definition_ty = if generics.parent.is_some() {
396+
// impl trait
397+
self.fcx.infer_anon_definition_from_instantiation(
398+
def_id,
399+
anon_defn,
400+
instantiated_ty,
401+
)
402+
} else {
402403
// prevent
403404
// * `fn foo<T>() -> Foo<T>`
404405
// * `fn foo<T: Bound + Other>() -> Foo<T>`
@@ -411,9 +412,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
411412
// fn foo<U>() -> Foo<U> { .. }
412413
// ```
413414
// figures out the concrete type with `U`, but the stored type is with `T`
414-
definition_ty = definition_ty.fold_with(&mut BottomUpFolder {
415+
instantiated_ty.fold_with(&mut BottomUpFolder {
415416
tcx: self.tcx().global_tcx(),
416417
fldop: |ty| {
418+
trace!("checking type {:?}: {:#?}", ty, ty.sty);
417419
// find a type parameter
418420
if let ty::TyParam(..) = ty.sty {
419421
// look it up in the substitution list
@@ -445,8 +447,50 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
445447
}
446448
ty
447449
},
448-
});
449-
}
450+
reg_op: |region| {
451+
match region {
452+
// ignore static regions
453+
ty::ReStatic => region,
454+
_ => {
455+
trace!("checking {:?}", region);
456+
for (subst, p) in anon_defn.substs.iter().zip(&generics.params) {
457+
if let UnpackedKind::Lifetime(subst) = subst.unpack() {
458+
if subst == region {
459+
// found it in the substitution list, replace with the
460+
// parameter from the existential type
461+
let reg = ty::EarlyBoundRegion {
462+
def_id: p.def_id,
463+
index: p.index,
464+
name: p.name,
465+
};
466+
trace!("replace {:?} with {:?}", region, reg);
467+
return self.tcx().global_tcx()
468+
.mk_region(ty::ReEarlyBound(reg));
469+
}
470+
}
471+
}
472+
trace!("anon_defn: {:#?}", anon_defn);
473+
trace!("generics: {:#?}", generics);
474+
self.tcx().sess
475+
.struct_span_err(
476+
span,
477+
"non-defining existential type use in defining scope",
478+
)
479+
.span_label(
480+
span,
481+
format!(
482+
"lifetime `{}` is part of concrete type but not used \
483+
in parameter list of existential type",
484+
region,
485+
),
486+
)
487+
.emit();
488+
self.tcx().global_tcx().mk_region(ty::ReStatic)
489+
}
490+
}
491+
}
492+
})
493+
};
450494

451495
let old = self.tables.concrete_existential_types.insert(def_id, definition_ty);
452496
if let Some(old) = old {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
#![feature(existential_type)]
13+
14+
fn main() {}
15+
16+
existential type Two<'a, 'b>: std::fmt::Debug;
17+
18+
fn one<'a>(t: &'a ()) -> Two<'a, 'a> { //~ ERROR non-defining existential type use
19+
t
20+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: non-defining existential type use in defining scope
2+
--> $DIR/generic_duplicate_lifetime_param.rs:18:1
3+
|
4+
LL | / fn one<'a>(t: &'a ()) -> Two<'a, 'a> { //~ ERROR non-defining existential type use
5+
LL | | t
6+
LL | | }
7+
| |_^
8+
|
9+
note: lifetime used multiple times
10+
--> $DIR/generic_duplicate_lifetime_param.rs:16:22
11+
|
12+
LL | existential type Two<'a, 'b>: std::fmt::Debug;
13+
| ^^ ^^
14+
15+
error: aborting due to previous error
16+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
#![feature(existential_type)]
13+
14+
fn main() {}
15+
16+
existential type Two<T, U>: 'static; //~ ERROR type parameter `U` is unused
17+
18+
fn one<T: 'static>(t: T) -> Two<T, T> {
19+
t
20+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0091]: type parameter `U` is unused
2+
--> $DIR/generic_duplicate_param_use.rs:16:25
3+
|
4+
LL | existential type Two<T, U>: 'static; //~ ERROR type parameter `U` is unused
5+
| ^ unused type parameter
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0091`.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-pass
12+
13+
#![feature(existential_type)]
14+
15+
fn main() {}
16+
17+
existential type Region<'a>: std::fmt::Debug;
18+
19+
fn region<'b>(a: &'b ()) -> Region<'b> {
20+
a
21+
}

src/test/ui/existential_types/no_revealing_outside_defining_module.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,23 @@
1313

1414
fn main() {}
1515

16-
mod boo2 {
17-
mod boo {
18-
pub existential type Boo: ::std::fmt::Debug;
19-
fn bomp() -> Boo {
20-
""
21-
}
16+
mod boo {
17+
pub existential type Boo: ::std::fmt::Debug;
18+
fn bomp() -> Boo {
19+
""
2220
}
21+
}
2322

24-
// don't actually know the type here
23+
// don't actually know the type here
2524

26-
fn bomp2() {
27-
let _: &str = bomp(); //~ ERROR mismatched types
28-
}
25+
fn bomp2() {
26+
let _: &str = bomp(); //~ ERROR mismatched types
27+
}
2928

30-
fn bomp() -> boo::Boo {
31-
"" //~ ERROR mismatched types
32-
}
29+
fn bomp() -> boo::Boo {
30+
"" //~ ERROR mismatched types
3331
}
32+
33+
fn bomp_loop() -> boo::Boo {
34+
loop {}
35+
}

src/test/ui/existential_types/no_revealing_outside_defining_module.stderr

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
error[E0308]: mismatched types
2-
--> $DIR/no_revealing_outside_defining_module.rs:27:23
2+
--> $DIR/no_revealing_outside_defining_module.rs:26:19
33
|
4-
LL | let _: &str = bomp(); //~ ERROR mismatched types
5-
| ^^^^^^ expected &str, found anonymized type
4+
LL | let _: &str = bomp(); //~ ERROR mismatched types
5+
| ^^^^^^ expected &str, found anonymized type
66
|
77
= note: expected type `&str`
88
found type `Boo`
99

1010
error[E0308]: mismatched types
11-
--> $DIR/no_revealing_outside_defining_module.rs:31:9
11+
--> $DIR/no_revealing_outside_defining_module.rs:30:5
1212
|
13-
LL | fn bomp() -> boo::Boo {
14-
| -------- expected `Boo` because of return type
15-
LL | "" //~ ERROR mismatched types
16-
| ^^ expected anonymized type, found reference
13+
LL | fn bomp() -> boo::Boo {
14+
| -------- expected `Boo` because of return type
15+
LL | "" //~ ERROR mismatched types
16+
| ^^ expected anonymized type, found reference
1717
|
1818
= note: expected type `Boo`
1919
found type `&'static str`

0 commit comments

Comments
 (0)