diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index 2cb47c7beb53a..ae4d88704a098 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -653,6 +653,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { let tcx = self.infcx.tcx; value.fold_with(&mut BottomUpFolder { tcx, + reg_op: |reg| reg, fldop: |ty| { if let ty::TyAnon(def_id, substs) = ty.sty { // Check that this is `impl Trait` type is diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 1380d10e493a8..e4484041b065c 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -200,15 +200,18 @@ pub trait TypeVisitor<'tcx> : Sized { /////////////////////////////////////////////////////////////////////////// // Some sample folders -pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F> - where F: FnMut(Ty<'tcx>) -> Ty<'tcx> +pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G> + where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, + G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, pub fldop: F, + pub reg_op: G, } -impl<'a, 'gcx, 'tcx, F> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F> +impl<'a, 'gcx, 'tcx, F, G> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, + G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } @@ -216,6 +219,11 @@ impl<'a, 'gcx, 'tcx, F> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx let t1 = ty.super_fold_with(self); (self.fldop)(t1) } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + let r = r.super_fold_with(self); + (self.reg_op)(r) + } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index cd6a1e3fdba22..03ecb945cbd3c 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -575,9 +575,10 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( let anon_node_id = tcx.hir.as_local_node_id(def_id).unwrap(); if may_define_existential_type(tcx, fn_def_id, anon_node_id) { trace!("check_existential_types may define. Generics: {:#?}", generics); + let mut seen: FxHashMap<_, Vec<_>> = FxHashMap(); for (subst, param) in substs.iter().zip(&generics.params) { - if let ty::subst::UnpackedKind::Type(ty) = subst.unpack() { - match ty.sty { + match subst.unpack() { + ty::subst::UnpackedKind::Type(ty) => match ty.sty { ty::TyParam(..) => {}, // prevent `fn foo() -> Foo` from being defining _ => { @@ -597,11 +598,47 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( ), ) .emit(); - return tcx.types.err; }, - } // match ty - } // if let Type = subst + }, // match ty + ty::subst::UnpackedKind::Lifetime(region) => { + let param_span = tcx.def_span(param.def_id); + if let ty::ReStatic = region { + tcx + .sess + .struct_span_err( + span, + "non-defining existential type use \ + in defining scope", + ) + .span_label( + param_span, + "cannot use static lifetime, use a bound lifetime \ + instead or remove the lifetime parameter from the \ + existential type", + ) + .emit(); + } else { + seen.entry(region).or_default().push(param_span); + } + }, + } // match subst } // for (subst, param) + for (_, spans) in seen { + if spans.len() > 1 { + tcx + .sess + .struct_span_err( + span, + "non-defining existential type use \ + in defining scope", + ). + span_note( + spans, + "lifetime used multiple times", + ) + .emit(); + } + } } // if may_define_existential_type // now register the bounds on the parameters of the existential type @@ -631,6 +668,7 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( } // if let TyAnon ty }, + reg_op: |reg| reg, }); substituted_predicates } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index d82ad0d180bf5..b37f489b2c721 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -389,16 +389,17 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() { let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap(); let instantiated_ty = self.resolve(&anon_defn.concrete_ty, &node_id); - let mut definition_ty = self.fcx.infer_anon_definition_from_instantiation( - def_id, - anon_defn, - instantiated_ty, - ); let generics = self.tcx().generics_of(def_id); - // named existential type, not an impl trait - if generics.parent.is_none() { + let definition_ty = if generics.parent.is_some() { + // impl trait + self.fcx.infer_anon_definition_from_instantiation( + def_id, + anon_defn, + instantiated_ty, + ) + } else { // prevent // * `fn foo() -> Foo` // * `fn foo() -> Foo` @@ -411,9 +412,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // fn foo() -> Foo { .. } // ``` // figures out the concrete type with `U`, but the stored type is with `T` - definition_ty = definition_ty.fold_with(&mut BottomUpFolder { + instantiated_ty.fold_with(&mut BottomUpFolder { tcx: self.tcx().global_tcx(), fldop: |ty| { + trace!("checking type {:?}: {:#?}", ty, ty.sty); // find a type parameter if let ty::TyParam(..) = ty.sty { // look it up in the substitution list @@ -445,8 +447,50 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } ty }, - }); - } + reg_op: |region| { + match region { + // ignore static regions + ty::ReStatic => region, + _ => { + trace!("checking {:?}", region); + for (subst, p) in anon_defn.substs.iter().zip(&generics.params) { + if let UnpackedKind::Lifetime(subst) = subst.unpack() { + if subst == region { + // found it in the substitution list, replace with the + // parameter from the existential type + let reg = ty::EarlyBoundRegion { + def_id: p.def_id, + index: p.index, + name: p.name, + }; + trace!("replace {:?} with {:?}", region, reg); + return self.tcx().global_tcx() + .mk_region(ty::ReEarlyBound(reg)); + } + } + } + trace!("anon_defn: {:#?}", anon_defn); + trace!("generics: {:#?}", generics); + self.tcx().sess + .struct_span_err( + span, + "non-defining existential type use in defining scope", + ) + .span_label( + span, + format!( + "lifetime `{}` is part of concrete type but not used \ + in parameter list of existential type", + region, + ), + ) + .emit(); + self.tcx().global_tcx().mk_region(ty::ReStatic) + } + } + } + }) + }; let old = self.tables.concrete_existential_types.insert(def_id, definition_ty); if let Some(old) = old { diff --git a/src/test/ui/existential_types/generic_duplicate_lifetime_param.rs b/src/test/ui/existential_types/generic_duplicate_lifetime_param.rs new file mode 100644 index 0000000000000..92b234aa6dc63 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_lifetime_param.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +#![feature(existential_type)] + +fn main() {} + +existential type Two<'a, 'b>: std::fmt::Debug; + +fn one<'a>(t: &'a ()) -> Two<'a, 'a> { //~ ERROR non-defining existential type use + t +} diff --git a/src/test/ui/existential_types/generic_duplicate_lifetime_param.stderr b/src/test/ui/existential_types/generic_duplicate_lifetime_param.stderr new file mode 100644 index 0000000000000..0316832a1af90 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_lifetime_param.stderr @@ -0,0 +1,16 @@ +error: non-defining existential type use in defining scope + --> $DIR/generic_duplicate_lifetime_param.rs:18:1 + | +LL | / fn one<'a>(t: &'a ()) -> Two<'a, 'a> { //~ ERROR non-defining existential type use +LL | | t +LL | | } + | |_^ + | +note: lifetime used multiple times + --> $DIR/generic_duplicate_lifetime_param.rs:16:22 + | +LL | existential type Two<'a, 'b>: std::fmt::Debug; + | ^^ ^^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/generic_duplicate_param_use.rs b/src/test/ui/existential_types/generic_duplicate_param_use.rs new file mode 100644 index 0000000000000..52e36fa9b6153 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +#![feature(existential_type)] + +fn main() {} + +existential type Two: 'static; //~ ERROR type parameter `U` is unused + +fn one(t: T) -> Two { + t +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use.stderr b/src/test/ui/existential_types/generic_duplicate_param_use.stderr new file mode 100644 index 0000000000000..e4a92dba58f3e --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use.stderr @@ -0,0 +1,9 @@ +error[E0091]: type parameter `U` is unused + --> $DIR/generic_duplicate_param_use.rs:16:25 + | +LL | existential type Two: 'static; //~ ERROR type parameter `U` is unused + | ^ unused type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0091`. diff --git a/src/test/ui/existential_types/generic_lifetime_param.rs b/src/test/ui/existential_types/generic_lifetime_param.rs new file mode 100644 index 0000000000000..3bdb69eec7f3e --- /dev/null +++ b/src/test/ui/existential_types/generic_lifetime_param.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![feature(existential_type)] + +fn main() {} + +existential type Region<'a>: std::fmt::Debug; + +fn region<'b>(a: &'b ()) -> Region<'b> { + a +} diff --git a/src/test/ui/existential_types/no_revealing_outside_defining_module.rs b/src/test/ui/existential_types/no_revealing_outside_defining_module.rs index 086df13ba7055..41c17c357bc80 100644 --- a/src/test/ui/existential_types/no_revealing_outside_defining_module.rs +++ b/src/test/ui/existential_types/no_revealing_outside_defining_module.rs @@ -13,21 +13,23 @@ fn main() {} -mod boo2 { - mod boo { - pub existential type Boo: ::std::fmt::Debug; - fn bomp() -> Boo { - "" - } +mod boo { + pub existential type Boo: ::std::fmt::Debug; + fn bomp() -> Boo { + "" } +} - // don't actually know the type here +// don't actually know the type here - fn bomp2() { - let _: &str = bomp(); //~ ERROR mismatched types - } +fn bomp2() { + let _: &str = bomp(); //~ ERROR mismatched types +} - fn bomp() -> boo::Boo { - "" //~ ERROR mismatched types - } +fn bomp() -> boo::Boo { + "" //~ ERROR mismatched types } + +fn bomp_loop() -> boo::Boo { + loop {} +} \ No newline at end of file diff --git a/src/test/ui/existential_types/no_revealing_outside_defining_module.stderr b/src/test/ui/existential_types/no_revealing_outside_defining_module.stderr index eebd329548936..a1c98c6d4b89e 100644 --- a/src/test/ui/existential_types/no_revealing_outside_defining_module.stderr +++ b/src/test/ui/existential_types/no_revealing_outside_defining_module.stderr @@ -1,19 +1,19 @@ error[E0308]: mismatched types - --> $DIR/no_revealing_outside_defining_module.rs:27:23 + --> $DIR/no_revealing_outside_defining_module.rs:26:19 | -LL | let _: &str = bomp(); //~ ERROR mismatched types - | ^^^^^^ expected &str, found anonymized type +LL | let _: &str = bomp(); //~ ERROR mismatched types + | ^^^^^^ expected &str, found anonymized type | = note: expected type `&str` found type `Boo` error[E0308]: mismatched types - --> $DIR/no_revealing_outside_defining_module.rs:31:9 + --> $DIR/no_revealing_outside_defining_module.rs:30:5 | -LL | fn bomp() -> boo::Boo { - | -------- expected `Boo` because of return type -LL | "" //~ ERROR mismatched types - | ^^ expected anonymized type, found reference +LL | fn bomp() -> boo::Boo { + | -------- expected `Boo` because of return type +LL | "" //~ ERROR mismatched types + | ^^ expected anonymized type, found reference | = note: expected type `Boo` found type `&'static str`