From 53d2ebb0adbe677a811ae130523ebceb285a8029 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 3 Jul 2018 19:38:14 +0200 Subject: [PATCH 01/16] Implement existential types --- src/librustc/hir/def.rs | 7 +- src/librustc/hir/intravisit.rs | 4 + src/librustc/hir/lowering.rs | 15 +- src/librustc/hir/map/def_collector.rs | 5 +- src/librustc/hir/map/definitions.rs | 4 + src/librustc/hir/map/mod.rs | 6 +- src/librustc/hir/mod.rs | 6 +- src/librustc/hir/print.rs | 12 +- src/librustc/ich/impls_hir.rs | 3 + src/librustc/ich/impls_ty.rs | 1 + src/librustc/infer/anon_types/mod.rs | 50 ++++++ src/librustc/infer/error_reporting/mod.rs | 4 +- src/librustc/middle/dead.rs | 1 + src/librustc/middle/reachable.rs | 2 + src/librustc/middle/resolve_lifetime.rs | 71 ++++++--- src/librustc/ty/item_path.rs | 1 + src/librustc/ty/mod.rs | 19 ++- src/librustc/ty/sty.rs | 6 +- src/librustc/util/ppaux.rs | 15 ++ .../persist/dirty_clean.rs | 1 + src/librustc_lint/builtin.rs | 1 + src/librustc_metadata/decoder.rs | 1 + src/librustc_metadata/encoder.rs | 5 + src/librustc_metadata/schema.rs | 2 + src/librustc_privacy/lib.rs | 7 +- src/librustc_resolve/build_reduced_graph.rs | 5 + src/librustc_resolve/lib.rs | 16 +- src/librustc_save_analysis/dump_visitor.rs | 40 +++++ src/librustc_save_analysis/lib.rs | 1 + src/librustc_save_analysis/sig.rs | 12 ++ src/librustc_typeck/astconv.rs | 25 ++- src/librustc_typeck/check/method/probe.rs | 1 + src/librustc_typeck/check/mod.rs | 2 + src/librustc_typeck/check/wfcheck.rs | 97 +++++++++++- src/librustc_typeck/check/writeback.rs | 59 ++++++- src/librustc_typeck/collect.rs | 144 ++++++++++++++++-- src/librustc_typeck/namespace.rs | 2 + src/librustdoc/clean/mod.rs | 32 ++++ src/librustdoc/doctree.rs | 13 ++ src/librustdoc/html/item_type.rs | 4 + src/librustdoc/html/render.rs | 5 + src/librustdoc/passes/mod.rs | 1 + src/librustdoc/visit_ast.rs | 16 +- src/libsyntax/ast.rs | 6 + src/libsyntax/feature_gate.rs | 21 +++ src/libsyntax/fold.rs | 7 + src/libsyntax/parse/parser.rs | 73 ++++++--- src/libsyntax/print/pprust.rs | 24 ++- src/libsyntax/visit.rs | 7 + src/libsyntax_pos/symbol.rs | 1 + src/test/parse-fail/issue-20711-2.rs | 3 +- src/test/parse-fail/issue-20711.rs | 3 +- .../parse-fail/removed-syntax-static-fn.rs | 3 +- src/test/run-pass/existential_type.rs | 113 ++++++++++++++ src/test/ui/{suggestions => }/as-ref.rs | 0 src/test/ui/{suggestions => }/as-ref.stderr | 0 src/test/ui/{suggestions => }/auxiliary/m1.rs | 0 src/test/ui/{suggestions => }/auxiliary/m2.rs | 0 .../auxiliary/macro-in-other-crate.rs | 0 .../auxiliary/removing-extern-crate.rs | 0 .../closure-immutable-outer-variable.fixed | 0 ...losure-immutable-outer-variable.nll.stderr | 0 .../closure-immutable-outer-variable.rs | 0 .../closure-immutable-outer-variable.rs.fixed | 0 .../closure-immutable-outer-variable.stderr | 0 .../confuse-field-and-method/issue-18343.rs | 0 .../issue-18343.stderr | 0 .../confuse-field-and-method/issue-2392.rs | 0 .../issue-2392.stderr | 0 .../confuse-field-and-method/issue-32128.rs | 0 .../issue-32128.stderr | 0 .../confuse-field-and-method/issue-33784.rs | 0 .../issue-33784.stderr | 0 .../confuse-field-and-method/private-field.rs | 0 .../private-field.stderr | 0 .../{suggestions => }/const-type-mismatch.rs | 0 .../const-type-mismatch.stderr | 0 .../{suggestions => }/conversion-methods.rs | 0 .../conversion-methods.stderr | 0 .../dont-suggest-private-trait-method.rs | 0 .../dont-suggest-private-trait-method.stderr | 0 .../ui/{suggestions => }/dotdotdot-expr.rs | 0 .../{suggestions => }/dotdotdot-expr.stderr | 0 src/test/ui/existential_type.nll.stderr | 111 ++++++++++++++ src/test/ui/existential_type.rs | 95 ++++++++++++ src/test/ui/existential_type.stderr | 120 +++++++++++++++ src/test/ui/existential_type2.rs | 30 ++++ src/test/ui/existential_type2.stderr | 23 +++ src/test/ui/existential_type3.rs | 21 +++ src/test/ui/existential_type3.stderr | 12 ++ ...ariable.nll.fixed => existential_type4.rs} | 17 +-- src/test/ui/existential_type4.stderr | 16 ++ .../{suggestions => }/extern-crate-rename.rs | 0 .../extern-crate-rename.stderr | 0 src/test/ui/feature-gate-existential-type.rs | 25 +++ .../ui/feature-gate-existential-type.stderr | 19 +++ .../fn-closure-mutable-capture.nll.stderr | 0 .../fn-closure-mutable-capture.rs | 0 .../fn-closure-mutable-capture.stderr | 0 src/test/ui/{suggestions => }/for-c-in-str.rs | 0 .../ui/{suggestions => }/for-c-in-str.stderr | 0 .../issue-32354-suggest-import-rename.fixed | 0 .../issue-32354-suggest-import-rename.rs | 0 .../issue-32354-suggest-import-rename.stderr | 0 .../issue-43420-no-over-suggest.rs | 0 .../issue-43420-no-over-suggest.stderr | 0 .../ui/{suggestions => }/issue-45562.fixed | 0 src/test/ui/{suggestions => }/issue-45562.rs | 0 .../ui/{suggestions => }/issue-45562.stderr | 0 ...n-crate-rename-suggestion-formatting.fixed | 0 ...tern-crate-rename-suggestion-formatting.rs | 0 ...-crate-rename-suggestion-formatting.stderr | 0 src/test/ui/{suggestions => }/issue-46302.rs | 0 .../ui/{suggestions => }/issue-46302.stderr | 0 ...6-consider-borrowing-cast-or-binexpr.fixed | 0 ...6756-consider-borrowing-cast-or-binexpr.rs | 0 ...-consider-borrowing-cast-or-binexpr.stderr | 0 src/test/ui/{suggestions => }/issue-48364.rs | 0 .../ui/{suggestions => }/issue-48364.stderr | 0 .../{suggestions => }/issue-51244.nll.stderr | 0 src/test/ui/{suggestions => }/issue-51244.rs | 0 .../ui/{suggestions => }/issue-51244.stderr | 0 src/test/ui/{suggestions => }/issue-51515.rs | 0 .../ui/{suggestions => }/issue-51515.stderr | 0 .../{suggestions => }/issue-52049.nll.stderr | 0 src/test/ui/{suggestions => }/issue-52049.rs | 0 .../ui/{suggestions => }/issue-52049.stderr | 0 .../method-on-ambiguous-numeric-type.rs | 0 .../method-on-ambiguous-numeric-type.stderr | 0 .../missing-comma-in-match.fixed | 0 .../missing-comma-in-match.rs | 0 .../missing-comma-in-match.stderr | 0 .../ui/{suggestions => }/numeric-cast-2.rs | 0 .../{suggestions => }/numeric-cast-2.stderr | 0 src/test/ui/{suggestions => }/numeric-cast.rs | 0 .../ui/{suggestions => }/numeric-cast.stderr | 0 .../ui/{suggestions => }/placement-syntax.rs | 0 .../{suggestions => }/placement-syntax.stderr | 0 .../ui/{suggestions => }/pub-ident-fn-2.rs | 0 .../{suggestions => }/pub-ident-fn-2.stderr | 0 .../pub-ident-fn-or-struct-2.rs | 0 .../pub-ident-fn-or-struct-2.stderr | 0 .../pub-ident-fn-or-struct.rs | 0 .../pub-ident-fn-or-struct.stderr | 0 .../ui/{suggestions => }/pub-ident-fn.fixed | 0 src/test/ui/{suggestions => }/pub-ident-fn.rs | 0 .../ui/{suggestions => }/pub-ident-fn.stderr | 0 .../ui/{suggestions => }/pub-ident-struct.rs | 0 .../{suggestions => }/pub-ident-struct.stderr | 0 .../removing-extern-crate.fixed | 0 .../removing-extern-crate.rs | 0 .../removing-extern-crate.stderr | 0 src/test/ui/{suggestions => }/repr.rs | 0 src/test/ui/{suggestions => }/repr.stderr | 0 src/test/ui/{suggestions => }/return-type.rs | 0 .../ui/{suggestions => }/return-type.stderr | 0 .../one-use-in-fn-argument-in-band.stderr | 24 +-- .../{suggestions => }/str-array-assignment.rs | 0 .../str-array-assignment.stderr | 0 .../ui/{suggestions => }/str-as-char.fixed | 0 src/test/ui/{suggestions => }/str-as-char.rs | 0 .../ui/{suggestions => }/str-as-char.stderr | 0 .../ui/{suggestions => }/suggest-labels.rs | 0 .../{suggestions => }/suggest-labels.stderr | 0 .../ui/{suggestions => }/suggest-methods.rs | 0 .../{suggestions => }/suggest-methods.stderr | 0 .../ui/{suggestions => }/suggest-ref-mut.rs | 0 .../{suggestions => }/suggest-ref-mut.stderr | 0 src/test/ui/token/issue-41155.stderr | 4 +- .../ui/{suggestions => }/try-on-option.rs | 0 .../ui/{suggestions => }/try-on-option.stderr | 0 .../{suggestions => }/try-operator-on-main.rs | 0 .../try-operator-on-main.stderr | 0 .../{suggestions => }/tuple-float-index.fixed | 0 .../ui/{suggestions => }/tuple-float-index.rs | 0 .../tuple-float-index.stderr | 0 .../type-ascription-instead-of-initializer.rs | 0 ...e-ascription-instead-of-initializer.stderr | 0 ...ype-ascription-instead-of-statement-end.rs | 0 ...ascription-instead-of-statement-end.stderr | 0 .../type-ascription-with-fn-call.rs | 0 .../type-ascription-with-fn-call.stderr | 0 182 files changed, 1385 insertions(+), 117 deletions(-) create mode 100644 src/test/run-pass/existential_type.rs rename src/test/ui/{suggestions => }/as-ref.rs (100%) rename src/test/ui/{suggestions => }/as-ref.stderr (100%) rename src/test/ui/{suggestions => }/auxiliary/m1.rs (100%) rename src/test/ui/{suggestions => }/auxiliary/m2.rs (100%) rename src/test/ui/{suggestions => }/auxiliary/macro-in-other-crate.rs (100%) rename src/test/ui/{suggestions => }/auxiliary/removing-extern-crate.rs (100%) rename src/test/ui/{suggestions => }/closure-immutable-outer-variable.fixed (100%) rename src/test/ui/{suggestions => }/closure-immutable-outer-variable.nll.stderr (100%) rename src/test/ui/{suggestions => }/closure-immutable-outer-variable.rs (100%) rename src/test/ui/{suggestions => }/closure-immutable-outer-variable.rs.fixed (100%) rename src/test/ui/{suggestions => }/closure-immutable-outer-variable.stderr (100%) rename src/test/ui/{suggestions => }/confuse-field-and-method/issue-18343.rs (100%) rename src/test/ui/{suggestions => }/confuse-field-and-method/issue-18343.stderr (100%) rename src/test/ui/{suggestions => }/confuse-field-and-method/issue-2392.rs (100%) rename src/test/ui/{suggestions => }/confuse-field-and-method/issue-2392.stderr (100%) rename src/test/ui/{suggestions => }/confuse-field-and-method/issue-32128.rs (100%) rename src/test/ui/{suggestions => }/confuse-field-and-method/issue-32128.stderr (100%) rename src/test/ui/{suggestions => }/confuse-field-and-method/issue-33784.rs (100%) rename src/test/ui/{suggestions => }/confuse-field-and-method/issue-33784.stderr (100%) rename src/test/ui/{suggestions => }/confuse-field-and-method/private-field.rs (100%) rename src/test/ui/{suggestions => }/confuse-field-and-method/private-field.stderr (100%) rename src/test/ui/{suggestions => }/const-type-mismatch.rs (100%) rename src/test/ui/{suggestions => }/const-type-mismatch.stderr (100%) rename src/test/ui/{suggestions => }/conversion-methods.rs (100%) rename src/test/ui/{suggestions => }/conversion-methods.stderr (100%) rename src/test/ui/{suggestions => }/dont-suggest-private-trait-method.rs (100%) rename src/test/ui/{suggestions => }/dont-suggest-private-trait-method.stderr (100%) rename src/test/ui/{suggestions => }/dotdotdot-expr.rs (100%) rename src/test/ui/{suggestions => }/dotdotdot-expr.stderr (100%) create mode 100644 src/test/ui/existential_type.nll.stderr create mode 100644 src/test/ui/existential_type.rs create mode 100644 src/test/ui/existential_type.stderr create mode 100644 src/test/ui/existential_type2.rs create mode 100644 src/test/ui/existential_type2.stderr create mode 100644 src/test/ui/existential_type3.rs create mode 100644 src/test/ui/existential_type3.stderr rename src/test/ui/{suggestions/closure-immutable-outer-variable.nll.fixed => existential_type4.rs} (56%) create mode 100644 src/test/ui/existential_type4.stderr rename src/test/ui/{suggestions => }/extern-crate-rename.rs (100%) rename src/test/ui/{suggestions => }/extern-crate-rename.stderr (100%) create mode 100644 src/test/ui/feature-gate-existential-type.rs create mode 100644 src/test/ui/feature-gate-existential-type.stderr rename src/test/ui/{suggestions => }/fn-closure-mutable-capture.nll.stderr (100%) rename src/test/ui/{suggestions => }/fn-closure-mutable-capture.rs (100%) rename src/test/ui/{suggestions => }/fn-closure-mutable-capture.stderr (100%) rename src/test/ui/{suggestions => }/for-c-in-str.rs (100%) rename src/test/ui/{suggestions => }/for-c-in-str.stderr (100%) rename src/test/ui/{suggestions => }/issue-32354-suggest-import-rename.fixed (100%) rename src/test/ui/{suggestions => }/issue-32354-suggest-import-rename.rs (100%) rename src/test/ui/{suggestions => }/issue-32354-suggest-import-rename.stderr (100%) rename src/test/ui/{suggestions => }/issue-43420-no-over-suggest.rs (100%) rename src/test/ui/{suggestions => }/issue-43420-no-over-suggest.stderr (100%) rename src/test/ui/{suggestions => }/issue-45562.fixed (100%) rename src/test/ui/{suggestions => }/issue-45562.rs (100%) rename src/test/ui/{suggestions => }/issue-45562.stderr (100%) rename src/test/ui/{suggestions => }/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed (100%) rename src/test/ui/{suggestions => }/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs (100%) rename src/test/ui/{suggestions => }/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr (100%) rename src/test/ui/{suggestions => }/issue-46302.rs (100%) rename src/test/ui/{suggestions => }/issue-46302.stderr (100%) rename src/test/ui/{suggestions => }/issue-46756-consider-borrowing-cast-or-binexpr.fixed (100%) rename src/test/ui/{suggestions => }/issue-46756-consider-borrowing-cast-or-binexpr.rs (100%) rename src/test/ui/{suggestions => }/issue-46756-consider-borrowing-cast-or-binexpr.stderr (100%) rename src/test/ui/{suggestions => }/issue-48364.rs (100%) rename src/test/ui/{suggestions => }/issue-48364.stderr (100%) rename src/test/ui/{suggestions => }/issue-51244.nll.stderr (100%) rename src/test/ui/{suggestions => }/issue-51244.rs (100%) rename src/test/ui/{suggestions => }/issue-51244.stderr (100%) rename src/test/ui/{suggestions => }/issue-51515.rs (100%) rename src/test/ui/{suggestions => }/issue-51515.stderr (100%) rename src/test/ui/{suggestions => }/issue-52049.nll.stderr (100%) rename src/test/ui/{suggestions => }/issue-52049.rs (100%) rename src/test/ui/{suggestions => }/issue-52049.stderr (100%) rename src/test/ui/{suggestions => }/method-on-ambiguous-numeric-type.rs (100%) rename src/test/ui/{suggestions => }/method-on-ambiguous-numeric-type.stderr (100%) rename src/test/ui/{suggestions => }/missing-comma-in-match.fixed (100%) rename src/test/ui/{suggestions => }/missing-comma-in-match.rs (100%) rename src/test/ui/{suggestions => }/missing-comma-in-match.stderr (100%) rename src/test/ui/{suggestions => }/numeric-cast-2.rs (100%) rename src/test/ui/{suggestions => }/numeric-cast-2.stderr (100%) rename src/test/ui/{suggestions => }/numeric-cast.rs (100%) rename src/test/ui/{suggestions => }/numeric-cast.stderr (100%) rename src/test/ui/{suggestions => }/placement-syntax.rs (100%) rename src/test/ui/{suggestions => }/placement-syntax.stderr (100%) rename src/test/ui/{suggestions => }/pub-ident-fn-2.rs (100%) rename src/test/ui/{suggestions => }/pub-ident-fn-2.stderr (100%) rename src/test/ui/{suggestions => }/pub-ident-fn-or-struct-2.rs (100%) rename src/test/ui/{suggestions => }/pub-ident-fn-or-struct-2.stderr (100%) rename src/test/ui/{suggestions => }/pub-ident-fn-or-struct.rs (100%) rename src/test/ui/{suggestions => }/pub-ident-fn-or-struct.stderr (100%) rename src/test/ui/{suggestions => }/pub-ident-fn.fixed (100%) rename src/test/ui/{suggestions => }/pub-ident-fn.rs (100%) rename src/test/ui/{suggestions => }/pub-ident-fn.stderr (100%) rename src/test/ui/{suggestions => }/pub-ident-struct.rs (100%) rename src/test/ui/{suggestions => }/pub-ident-struct.stderr (100%) rename src/test/ui/{suggestions => }/removing-extern-crate.fixed (100%) rename src/test/ui/{suggestions => }/removing-extern-crate.rs (100%) rename src/test/ui/{suggestions => }/removing-extern-crate.stderr (100%) rename src/test/ui/{suggestions => }/repr.rs (100%) rename src/test/ui/{suggestions => }/repr.stderr (100%) rename src/test/ui/{suggestions => }/return-type.rs (100%) rename src/test/ui/{suggestions => }/return-type.stderr (100%) rename src/test/ui/{suggestions => }/str-array-assignment.rs (100%) rename src/test/ui/{suggestions => }/str-array-assignment.stderr (100%) rename src/test/ui/{suggestions => }/str-as-char.fixed (100%) rename src/test/ui/{suggestions => }/str-as-char.rs (100%) rename src/test/ui/{suggestions => }/str-as-char.stderr (100%) rename src/test/ui/{suggestions => }/suggest-labels.rs (100%) rename src/test/ui/{suggestions => }/suggest-labels.stderr (100%) rename src/test/ui/{suggestions => }/suggest-methods.rs (100%) rename src/test/ui/{suggestions => }/suggest-methods.stderr (100%) rename src/test/ui/{suggestions => }/suggest-ref-mut.rs (100%) rename src/test/ui/{suggestions => }/suggest-ref-mut.stderr (100%) rename src/test/ui/{suggestions => }/try-on-option.rs (100%) rename src/test/ui/{suggestions => }/try-on-option.stderr (100%) rename src/test/ui/{suggestions => }/try-operator-on-main.rs (100%) rename src/test/ui/{suggestions => }/try-operator-on-main.stderr (100%) rename src/test/ui/{suggestions => }/tuple-float-index.fixed (100%) rename src/test/ui/{suggestions => }/tuple-float-index.rs (100%) rename src/test/ui/{suggestions => }/tuple-float-index.stderr (100%) rename src/test/ui/{suggestions => }/type-ascription-instead-of-initializer.rs (100%) rename src/test/ui/{suggestions => }/type-ascription-instead-of-initializer.stderr (100%) rename src/test/ui/{suggestions => }/type-ascription-instead-of-statement-end.rs (100%) rename src/test/ui/{suggestions => }/type-ascription-instead-of-statement-end.stderr (100%) rename src/test/ui/{suggestions => }/type-ascription-with-fn-call.rs (100%) rename src/test/ui/{suggestions => }/type-ascription-with-fn-call.stderr (100%) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 7a26a239aeffa..1c355e35fd6ea 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -37,11 +37,15 @@ pub enum Def { Enum(DefId), Variant(DefId), Trait(DefId), + /// `existential type Foo: Bar;` Existential(DefId), + /// `type Foo = Bar;` TyAlias(DefId), TyForeign(DefId), TraitAlias(DefId), AssociatedTy(DefId), + /// `existential type Foo: Bar;` + AssociatedExistential(DefId), PrimTy(hir::PrimTy), TyParam(DefId), SelfTy(Option /* trait */, Option /* impl */), @@ -245,7 +249,7 @@ impl Def { Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Macro(id, ..) | - Def::Existential(id) | + Def::Existential(id) | Def::AssociatedExistential(id) | Def::GlobalAsm(id) | Def::TyForeign(id) => { id } @@ -276,6 +280,7 @@ impl Def { Def::TyAlias(..) => "type alias", Def::TraitAlias(..) => "trait alias", Def::AssociatedTy(..) => "associated type", + Def::AssociatedExistential(..) => "associated existential type", Def::Struct(..) => "struct", Def::StructCtor(.., CtorKind::Fn) => "tuple struct", Def::StructCtor(.., CtorKind::Const) => "unit struct", diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2fefd2b33189c..4274cd3a0a655 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -907,6 +907,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt visitor.visit_id(impl_item.id); visitor.visit_ty(ty); } + ImplItemKind::Existential(ref bounds) => { + visitor.visit_id(impl_item.id); + walk_list!(visitor, visit_param_bound, bounds); + } } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 722934ac39a53..80e9b4caef5f1 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -323,6 +323,7 @@ impl<'a> LoweringContext<'a> { | ItemKind::Union(_, ref generics) | ItemKind::Enum(_, ref generics) | ItemKind::Ty(_, ref generics) + | ItemKind::Existential(_, ref generics) | ItemKind::Trait(_, _, ref generics, ..) => { let def_id = self.lctx.resolver.definitions().local_def_id(item.id); let count = generics @@ -2632,6 +2633,11 @@ impl<'a> LoweringContext<'a> { self.lower_ty(t, ImplTraitContext::Disallowed), self.lower_generics(generics, ImplTraitContext::Disallowed), ), + ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(hir::ExistTy { + generics: self.lower_generics(generics, ImplTraitContext::Disallowed), + bounds: self.lower_param_bounds(b, ImplTraitContext::Disallowed), + impl_trait_fn: None, + }), ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum( hir::EnumDef { variants: enum_definition @@ -3037,6 +3043,12 @@ impl<'a> LoweringContext<'a> { self.lower_generics(&i.generics, ImplTraitContext::Disallowed), hir::ImplItemKind::Type(self.lower_ty(ty, ImplTraitContext::Disallowed)), ), + ImplItemKind::Existential(ref bounds) => ( + self.lower_generics(&i.generics, ImplTraitContext::Disallowed), + hir::ImplItemKind::Existential( + self.lower_param_bounds(bounds, ImplTraitContext::Disallowed), + ), + ), ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), }; @@ -3065,6 +3077,7 @@ impl<'a> LoweringContext<'a> { kind: match i.node { ImplItemKind::Const(..) => hir::AssociatedItemKind::Const, ImplItemKind::Type(..) => hir::AssociatedItemKind::Type, + ImplItemKind::Existential(..) => hir::AssociatedItemKind::Existential, ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method { has_self: sig.decl.has_self(), }, @@ -4331,7 +4344,7 @@ impl<'a> LoweringContext<'a> { respan(v.span, node) } - fn lower_defaultness(&mut self, d: Defaultness, has_value: bool) -> hir::Defaultness { + fn lower_defaultness(&self, d: Defaultness, has_value: bool) -> hir::Defaultness { match d { Defaultness::Default => hir::Defaultness::Default { has_value: has_value, diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index c1de6c15d41b3..cab620aeec548 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -116,7 +116,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ItemKind::Impl(..) => DefPathData::Impl, ItemKind::Trait(..) => DefPathData::Trait(i.ident.as_interned_str()), ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | - ItemKind::TraitAlias(..) | + ItemKind::TraitAlias(..) | ItemKind::Existential(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.as_interned_str()), ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { @@ -250,6 +250,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::ValueNs(ii.ident.as_interned_str()), ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.as_interned_str()), + ImplItemKind::Existential(..) => { + DefPathData::AssocExistentialInImpl(ii.ident.as_interned_str()) + }, ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id), }; diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 9b1bb3310f2fd..c4b28fe2c4332 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -330,6 +330,8 @@ pub enum DefPathData { AssocTypeInTrait(InternedString), /// An associated type **value** (i.e., in an impl) AssocTypeInImpl(InternedString), + /// An existential associated type **value** (i.e., in an impl) + AssocExistentialInImpl(InternedString), /// Something in the type NS TypeNs(InternedString), /// Something in the value NS @@ -605,6 +607,7 @@ impl DefPathData { Trait(name) | AssocTypeInTrait(name) | AssocTypeInImpl(name) | + AssocExistentialInImpl(name) | ValueNs(name) | Module(name) | MacroDef(name) | @@ -631,6 +634,7 @@ impl DefPathData { Trait(name) | AssocTypeInTrait(name) | AssocTypeInImpl(name) | + AssocExistentialInImpl(name) | ValueNs(name) | Module(name) | MacroDef(name) | diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index d413a544c4e41..49231e58cf0fc 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -470,6 +470,7 @@ impl<'hir> Map<'hir> { ImplItemKind::Const(..) => Some(Def::AssociatedConst(def_id)), ImplItemKind::Method(..) => Some(Def::Method(def_id)), ImplItemKind::Type(..) => Some(Def::AssociatedTy(def_id)), + ImplItemKind::Existential(..) => Some(Def::AssociatedExistential(def_id)), } } NodeVariant(variant) => { @@ -1323,7 +1324,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemKind::ForeignMod(..) => "foreign mod", ItemKind::GlobalAsm(..) => "global asm", ItemKind::Ty(..) => "ty", - ItemKind::Existential(..) => "existential", + ItemKind::Existential(..) => "existential type", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", @@ -1347,6 +1348,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ImplItemKind::Type(_) => { format!("assoc type {} in {}{}", ii.ident, path_str(), id_str) } + ImplItemKind::Existential(_) => { + format!("assoc existential type {} in {}{}", ii.ident, path_str(), id_str) + } } } Some(NodeTraitItem(ti)) => { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c1a885d80bf8b..b16c97172f1c3 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1620,6 +1620,8 @@ pub enum ImplItemKind { Method(MethodSig, BodyId), /// An associated type Type(P), + /// An associated existential type + Existential(GenericBounds), } // Bind a type to an associated type: `A=Foo`. @@ -2080,7 +2082,7 @@ pub enum ItemKind { GlobalAsm(P), /// A type alias, e.g. `type Foo = Bar` Ty(P, Generics), - /// A type alias, e.g. `type Foo = Bar` + /// An existential type definition, e.g. `existential type Foo: Bar;` Existential(ExistTy), /// An enum definition, e.g. `enum Foo {C, D}` Enum(EnumDef, Generics), @@ -2138,6 +2140,7 @@ impl ItemKind { Some(match *self { ItemKind::Fn(_, _, ref generics, _) | ItemKind::Ty(_, ref generics) | + ItemKind::Existential(ExistTy { ref generics, impl_trait_fn: None, .. }) | ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) | @@ -2184,6 +2187,7 @@ pub enum AssociatedItemKind { Const, Method { has_self: bool }, Type, + Existential, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index e637a18d1cd0a..4499a378be21a 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -627,9 +627,7 @@ impl<'a> State<'a> { self.end()? } hir::ItemKind::Ty(ref ty, ref generics) => { - self.ibox(indent_unit)?; - self.ibox(0)?; - self.word_nbsp(&visibility_qualified(&item.vis, "type"))?; + self.head(&visibility_qualified(&item.vis, "type"))?; self.print_name(item.name)?; self.print_generic_params(&generics.params)?; self.end()?; // end the inner ibox @@ -642,9 +640,7 @@ impl<'a> State<'a> { self.end()?; // end the outer ibox } hir::ItemKind::Existential(ref exist) => { - self.ibox(indent_unit)?; - self.ibox(0)?; - self.word_nbsp(&visibility_qualified(&item.vis, "existential type"))?; + self.head(&visibility_qualified(&item.vis, "existential type"))?; self.print_name(item.name)?; self.print_generic_params(&exist.generics.params)?; self.end()?; // end the inner ibox @@ -994,6 +990,10 @@ impl<'a> State<'a> { hir::ImplItemKind::Type(ref ty) => { self.print_associated_type(ii.ident, None, Some(ty))?; } + hir::ImplItemKind::Existential(ref bounds) => { + self.word_space("existential")?; + self.print_associated_type(ii.ident, Some(bounds), None)?; + } } self.ann.post(self, NodeSubItem(ii.id)) } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index d1fb05ceafbfd..2ce7749172b19 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -701,6 +701,7 @@ impl<'a> HashStable> for hir::ImplItem { impl_stable_hash_for!(enum hir::ImplItemKind { Const(t, body), Method(sig, body), + Existential(bounds), Type(t) }); @@ -890,6 +891,7 @@ impl<'a> HashStable> for hir::AssociatedItemKind { mem::discriminant(self).hash_stable(hcx, hasher); match *self { hir::AssociatedItemKind::Const | + hir::AssociatedItemKind::Existential | hir::AssociatedItemKind::Type => { // No fields to hash. } @@ -997,6 +999,7 @@ impl_stable_hash_for!(enum hir::def::Def { TyAlias(def_id), TraitAlias(def_id), AssociatedTy(def_id), + AssociatedExistential(def_id), PrimTy(prim_ty), TyParam(def_id), SelfTy(trait_def_id, impl_def_id), diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index a3600c0480017..cb685f83aba1e 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1055,6 +1055,7 @@ impl_stable_hash_for!(struct ty::AssociatedItem { impl_stable_hash_for!(enum ty::AssociatedKind { Const, Method, + Existential, Type }); diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index 2924016670bf8..5e731871e2851 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -691,10 +691,22 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { // ``` if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) { let anon_parent_def_id = match tcx.hir.expect_item(anon_node_id).node { + // impl trait hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(parent), .. }) => parent, + // named existential types + hir::ItemKind::Existential(hir::ExistTy { + impl_trait_fn: None, + .. + }) if may_define_existential_type( + tcx, + self.parent_def_id, + anon_node_id, + ) => { + return self.fold_anon_ty(ty, def_id, substs); + }, _ => { let anon_parent_node_id = tcx.hir.get_parent(anon_node_id); tcx.hir.local_def_id(anon_parent_node_id) @@ -742,6 +754,10 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { let ty_var = infcx.next_ty_var(TypeVariableOrigin::TypeInference(span)); let predicates_of = tcx.predicates_of(def_id); + debug!( + "instantiate_anon_types: predicates: {:#?}", + predicates_of, + ); let bounds = predicates_of.instantiate(tcx, substs); debug!("instantiate_anon_types: bounds={:?}", bounds); @@ -751,6 +767,18 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { required_region_bounds ); + // make sure that we are in fact defining the *entire* type + // e.g. `existential type Foo: Bar;` needs to be + // defined by a function like `fn foo() -> Foo`. + debug!( + "instantiate_anon_types: param_env: {:#?}", + self.param_env, + ); + debug!( + "instantiate_anon_types: generics: {:#?}", + tcx.generics_of(def_id), + ); + self.anon_types.insert( def_id, AnonTypeDecl { @@ -778,3 +806,25 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { ty_var } } + +/// Whether `anon_node_id` is a sibling or a child of a sibling of `def_id` +pub fn may_define_existential_type( + tcx: TyCtxt, + def_id: DefId, + anon_node_id: ast::NodeId, +) -> bool { + let mut node_id = tcx + .hir + .as_local_node_id(def_id) + .unwrap(); + // named existential types can be defined by any siblings or + // children of siblings + let mod_id = tcx.hir.get_parent(anon_node_id); + // so we walk up the node tree until we hit the root or the parent + // of the anon type + while node_id != mod_id && node_id != ast::CRATE_NODE_ID { + node_id = tcx.hir.get_parent(node_id); + } + // syntactically we are allowed to define the concrete type + node_id == mod_id +} diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 8da0dc365b04e..1ec9c9489e9b7 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -279,7 +279,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str { match item.node { hir::ImplItemKind::Method(..) => "method body", - hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => "associated item", + hir::ImplItemKind::Const(..) | + hir::ImplItemKind::Existential(..) | + hir::ImplItemKind::Type(..) => "associated item", } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index da59bced760d4..aa1951efba37e 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -622,6 +622,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { } self.visit_nested_body(body_id) } + hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(..) => {} } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index a504697008ef4..7f4b0bb126bbe 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -210,6 +210,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } } } + hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(_) => false, } } @@ -319,6 +320,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { self.visit_nested_body(body) } } + hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(_) => {} } } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 05a6cd9c243d2..39a57e985e89b 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -627,6 +627,30 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { if let Def::Existential(exist_ty_did) = path.def { + let id = self.tcx.hir.as_local_node_id(exist_ty_did).unwrap(); + + // Resolve the lifetimes in the bounds to the lifetime defs in the generics. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `abstract type MyAnonTy<'b>: MyTrait<'b>;` + // ^ ^ this gets resolved in the scope of + // the exist_ty generics + let (generics, bounds) = match self.tcx.hir.expect_item(id).node { + // named existential types don't need these hacks + hir::ItemKind::Existential(hir::ExistTy{ impl_trait_fn: None, .. }) => { + intravisit::walk_ty(self, ty); + return; + }, + hir::ItemKind::Existential(hir::ExistTy{ + ref generics, + ref bounds, + .. + }) => ( + generics, + bounds, + ), + ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i), + }; + assert!(exist_ty_did.is_local()); // Resolve the lifetimes that are applied to the existential type. // These are resolved in the current scope. @@ -667,23 +691,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } - let id = self.tcx.hir.as_local_node_id(exist_ty_did).unwrap(); - - // Resolve the lifetimes in the bounds to the lifetime defs in the generics. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `abstract type MyAnonTy<'b>: MyTrait<'b>;` - // ^ ^ this gets resolved in the scope of - // the exist_ty generics - let (generics, bounds) = match self.tcx.hir.expect_item(id).node { - hir::ItemKind::Existential( - hir::ExistTy { ref generics, ref bounds, .. } - ) => ( - generics, - bounds, - ), - ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i), - }; - // We want to start our early-bound indices at the end of the parent scope, // not including any parent `impl Trait`s. let mut index = self.next_early_index_for_abstract_type(); @@ -847,6 +854,35 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.visit_ty(ty); }); } + Existential(ref bounds) => { + let generics = &impl_item.generics; + let mut index = self.next_early_index(); + let mut next_early_index = index; + debug!("visit_ty: index = {}", index); + let lifetimes = generics.params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir, &mut index, param)) + } + GenericParamKind::Type { .. } => { + next_early_index += 1; + None + } + }).collect(); + + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + track_lifetime_uses: true, + abstract_type_parent: true, + }; + self.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + } Const(_, _) => { // Only methods and types support generics. assert!(impl_item.generics.params.is_empty()); @@ -1213,6 +1249,7 @@ fn compute_object_lifetime_defaults( hir::ItemKind::Struct(_, ref generics) | hir::ItemKind::Union(_, ref generics) | hir::ItemKind::Enum(_, ref generics) + | hir::ItemKind::Existential(hir::ExistTy { ref generics, impl_trait_fn: None, .. }) | hir::ItemKind::Ty(_, ref generics) | hir::ItemKind::Trait(_, _, ref generics, ..) => { let result = object_lifetime_defaults_for_item(tcx, generics); diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 95da68bc9ffc2..a44962c77b5f5 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -212,6 +212,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::Trait(..) | data @ DefPathData::AssocTypeInTrait(..) | data @ DefPathData::AssocTypeInImpl(..) | + data @ DefPathData::AssocExistentialInImpl(..) | data @ DefPathData::ValueNs(..) | data @ DefPathData::Module(..) | data @ DefPathData::TypeParam(..) | diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5aa6542a027da..2e221424e3ce0 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -192,6 +192,7 @@ pub struct AssociatedItem { pub enum AssociatedKind { Const, Method, + Existential, Type } @@ -201,6 +202,7 @@ impl AssociatedItem { AssociatedKind::Const => Def::AssociatedConst(self.def_id), AssociatedKind::Method => Def::Method(self.def_id), AssociatedKind::Type => Def::AssociatedTy(self.def_id), + AssociatedKind::Existential => Def::AssociatedExistential(self.def_id), } } @@ -208,7 +210,8 @@ impl AssociatedItem { /// for ! pub fn relevant_for_never<'tcx>(&self) -> bool { match self.kind { - AssociatedKind::Const => true, + AssociatedKind::Existential | + AssociatedKind::Const | AssociatedKind::Type => true, // FIXME(canndrew): Be more thorough here, check if any argument is uninhabited. AssociatedKind::Method => !self.method_has_self_argument, @@ -225,6 +228,7 @@ impl AssociatedItem { format!("{}", tcx.fn_sig(self.def_id).skip_binder()) } ty::AssociatedKind::Type => format!("type {};", self.ident), + ty::AssociatedKind::Existential => format!("existential type {};", self.ident), ty::AssociatedKind::Const => { format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id)) } @@ -2491,6 +2495,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { (ty::AssociatedKind::Method, has_self) } hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false), + hir::AssociatedItemKind::Existential => bug!("only impls can have existentials"), }; AssociatedItem { @@ -2516,6 +2521,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { (ty::AssociatedKind::Method, has_self) } hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false), + hir::AssociatedItemKind::Existential => (ty::AssociatedKind::Existential, false), }; AssociatedItem { @@ -2857,8 +2863,15 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // The param_env of an existential type is its parent's param_env if let Some(Def::Existential(_)) = tcx.describe_def(def_id) { - let parent = tcx.parent_def_id(def_id).expect("impl trait item w/o a parent"); - return param_env(tcx, parent); + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + if let hir::map::NodeItem(item) = tcx.hir.get(node_id) { + if let hir::ItemKind::Existential(ref exist_ty) = item.node { + if let Some(parent) = exist_ty.impl_trait_fn { + return param_env(tcx, parent); + } + } + } + } } // Compute the bounds on Self and the type parameters. diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 934bf9a416a95..dd38188824338 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -158,8 +158,10 @@ pub enum TypeVariants<'tcx> { TyProjection(ProjectionTy<'tcx>), /// Anonymized (`impl Trait`) type found in a return type. - /// The DefId comes from the `impl Trait` ast::Ty node, and the - /// substitutions are for the generics of the function in question. + /// The DefId comes either from + /// * the `impl Trait` ast::Ty node, + /// * or the `existential type` declaration + /// The substitutions are for the generics of the function in question. /// After typeck, the concrete type can be found in the `types` map. TyAnon(DefId, &'tcx Substs<'tcx>), diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index c17fd79df2af0..c67453d2b201a 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -271,6 +271,7 @@ impl PrintContext { match key.disambiguated_data.data { DefPathData::AssocTypeInTrait(_) | DefPathData::AssocTypeInImpl(_) | + DefPathData::AssocExistentialInImpl(_) | DefPathData::Trait(_) | DefPathData::TypeNs(_) => { break; @@ -1081,6 +1082,20 @@ define_print! { } ty::tls::with(|tcx| { + let def_key = tcx.def_key(def_id); + if let Some(name) = def_key.disambiguated_data.data.get_opt_name() { + write!(f, "{}", name)?; + let mut substs = substs.iter(); + if let Some(first) = substs.next() { + write!(f, "::<")?; + write!(f, "{}", first)?; + for subst in substs { + write!(f, ", {}", subst)?; + } + write!(f, ">")?; + } + return Ok(()); + } // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. let predicates_of = tcx.predicates_of(def_id); diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 39e674a6095b6..7f2da5a326ace 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -417,6 +417,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { ImplItemKind::Method(..) => ("NodeImplItem", LABELS_FN_IN_IMPL), ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL), ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL), + ImplItemKind::Existential(..) => ("NodeImplType", LABELS_CONST_IN_IMPL), } }, _ => self.tcx.sess.span_fatal( diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 8a674449880b8..af40f3c64ed79 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -461,6 +461,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { hir::ImplItemKind::Const(..) => "an associated constant", hir::ImplItemKind::Method(..) => "a method", hir::ImplItemKind::Type(_) => "an associated type", + hir::ImplItemKind::Existential(_) => "an associated existential type", }; self.check_missing_docs_attrs(cx, Some(impl_item.id), diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b8c6438395066..ab566654c389c 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -421,6 +421,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Type => Def::TyAlias(did), EntryKind::Existential => Def::Existential(did), EntryKind::AssociatedType(_) => Def::AssociatedTy(did), + EntryKind::AssociatedExistential(_) => Def::AssociatedExistential(did), EntryKind::Mod(_) => Def::Mod(did), EntryKind::Variant(_) => Def::Variant(did), EntryKind::Trait(_) => Def::Trait(did), diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index b9cb97ed7d0c5..7ed991e0de3a1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -840,6 +840,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { })) } ty::AssociatedKind::Type => EntryKind::AssociatedType(container), + ty::AssociatedKind::Existential => + span_bug!(ast_item.span, "existential type in trait"), }; Entry { @@ -863,6 +865,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { None } } + ty::AssociatedKind::Existential => unreachable!(), }, inherent_impls: LazySeq::empty(), variances: if trait_item.kind == ty::AssociatedKind::Method { @@ -933,6 +936,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { has_self: impl_item.method_has_self_argument, })) } + ty::AssociatedKind::Existential => EntryKind::AssociatedExistential(container), ty::AssociatedKind::Type => EntryKind::AssociatedType(container) }; @@ -948,6 +952,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; needs_inline || is_const_fn || always_encode_mir }, + hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(..) => false, }; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 430cbf9b529fb..d7c54cbc81d94 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -321,6 +321,7 @@ pub enum EntryKind<'tcx> { Impl(Lazy>), Method(Lazy>), AssociatedType(AssociatedContainer), + AssociatedExistential(AssociatedContainer), AssociatedConst(AssociatedContainer, ConstQualif, Lazy), } @@ -382,6 +383,7 @@ impl<'a, 'gcx> HashStable> for EntryKind<'gcx> { EntryKind::Method(ref method_data) => { method_data.hash_stable(hcx, hasher); } + EntryKind::AssociatedExistential(associated_container) | EntryKind::AssociatedType(associated_container) => { associated_container.hash_stable(hcx, hasher); } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index ab383287773a1..7b13c98b31ddf 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -237,7 +237,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { hir::ItemKind::Use(..) => {} // The interface is empty hir::ItemKind::GlobalAsm(..) => {} - hir::ItemKind::Existential(..) => { + hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(_), .. }) => { if item_level.is_some() { // Reach the (potentially private) type and the API being exposed self.reach(item.id).ty().predicates(); @@ -245,6 +245,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } // Visit everything hir::ItemKind::Const(..) | hir::ItemKind::Static(..) | + hir::ItemKind::Existential(..) | hir::ItemKind::Fn(..) | hir::ItemKind::Ty(..) => { if item_level.is_some() { self.reach(item.id).generics().predicates().ty(); @@ -1165,6 +1166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { hir::ImplItemKind::Method(..) => { self.access_levels.is_reachable(impl_item.id) } + hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(_) => false, } }); @@ -1566,7 +1568,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> hir::ItemKind::Use(..) => {} // No subitems hir::ItemKind::GlobalAsm(..) => {} - hir::ItemKind::Existential(..) => { + hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(_), .. }) => { // Check the traits being exposed, as they're separate, // e.g. `impl Iterator` has two predicates, // `X: Iterator` and `::Item == T`, @@ -1577,6 +1579,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> } // Subitems of these items have inherited publicity hir::ItemKind::Const(..) | hir::ItemKind::Static(..) | hir::ItemKind::Fn(..) | + hir::ItemKind::Existential(..) | hir::ItemKind::Ty(..) => { self.check(item.id, item_visibility).generics().predicates().ty(); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 29312912a2423..e00919547fc43 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -361,6 +361,11 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); } + ItemKind::Existential(_, _) => { + let def = Def::Existential(self.definitions.local_def_id(item.id)); + self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); + } + ItemKind::Enum(ref enum_definition, _) => { let def = Def::Enum(self.definitions.local_def_id(item.id)); let module_kind = ModuleKind::Def(def, ident.name); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f388b911feb6a..617ae4b787f8f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -207,7 +207,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) | Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) | Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) | - Def::Existential(..) | + Def::Existential(..) | Def::AssociatedExistential(..) | Def::Macro(..) | Def::GlobalAsm(..) | Def::Err => bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \ Def::TyParam") @@ -535,6 +535,7 @@ impl<'a> PathSource<'a> { Def::Struct(..) | Def::Union(..) | Def::Enum(..) | Def::Trait(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) | + Def::Existential(..) | Def::TyForeign(..) => true, _ => false, }, @@ -2148,6 +2149,7 @@ impl<'a> Resolver<'a> { match item.node { ItemKind::Enum(_, ref generics) | ItemKind::Ty(_, ref generics) | + ItemKind::Existential(_, ref generics) | ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) | ItemKind::Fn(_, _, ref generics, _) => { @@ -2486,6 +2488,18 @@ impl<'a> Resolver<'a> { this.visit_ty(ty); } + ImplItemKind::Existential(ref bounds) => { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item(impl_item.ident, + TypeNS, + impl_item.span, + |n, s| TypeNotMemberOfTrait(n, s)); + + for bound in bounds { + this.visit_param_bound(bound); + } + } ImplItemKind::Macro(_) => panic!("unexpanded macro in resolve!"), } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 34dcdfb757f73..58189ee0a2f10 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1238,6 +1238,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { // trait. self.visit_ty(ty) } + ast::ImplItemKind::Existential(ref bounds) => { + // FIXME uses of the assoc type should ideally point to this + // 'def' and the name here should be a ref to the def in the + // trait. + for bound in bounds.iter() { + if let ast::GenericBound::Trait(ref trait_ref, _) = *bound { + self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path) + } + } + } ast::ImplItemKind::Macro(_) => {} } } @@ -1477,6 +1487,36 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc self.visit_ty(&ty); self.process_generic_params(ty_params, item.span, &qualname, item.id); } + Existential(ref _bounds, ref ty_params) => { + let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + // FIXME do something with _bounds + let value = String::new(); + let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type); + if !self.span.filter_generated(sub_span, item.span) { + let span = self.span_from_span(sub_span.expect("No span found for typedef")); + let id = ::id_from_node_id(item.id, &self.save_ctxt); + + self.dumper.dump_def( + &access_from!(self.save_ctxt, item), + Def { + kind: DefKind::Type, + id, + span, + name: item.ident.to_string(), + qualname: qualname.clone(), + value, + parent: None, + children: vec![], + decl_id: None, + docs: self.save_ctxt.docs_for_attrs(&item.attrs), + sig: sig::item_signature(item, &self.save_ctxt), + attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt), + }, + ); + } + + self.process_generic_params(ty_params, item.span, &qualname, item.id); + } Mac(_) => (), _ => visit::walk_item(self, item), } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index f2620c04754b8..c84f194f0232a 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -749,6 +749,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { HirDef::TyAlias(def_id) | HirDef::TyForeign(def_id) | HirDef::TraitAlias(def_id) | + HirDef::AssociatedExistential(def_id) | HirDef::AssociatedTy(def_id) | HirDef::Trait(def_id) | HirDef::Existential(def_id) | diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 70feba1eff866..130325628796e 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -444,6 +444,18 @@ impl Sig for ast::Item { refs: vec![], }) } + ast::ItemKind::Existential(ref bounds, ref generics) => { + let text = "existential type ".to_owned(); + let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?; + + if !bounds.is_empty() { + sig.text.push_str(": "); + sig.text.push_str(&pprust::bounds_to_string(bounds)); + } + sig.text.push(';'); + + Ok(sig) + } ast::ItemKind::Ty(ref ty, ref generics) => { let text = "type ".to_owned(); let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f85e7b0685889..60aea074f2421 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1035,6 +1035,26 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { let span = path.span; match path.def { + Def::Existential(did) => { + // check for desugared impl trait + if let Some(node_id) = tcx.hir.as_local_node_id(did) { + if let hir::map::NodeItem(item) = tcx.hir.get(node_id) { + if let hir::ItemKind::Existential(ref exist_ty) = item.node { + if exist_ty.impl_trait_fn.is_some() { + let lifetimes = &path.segments[0].args.as_ref().unwrap().args; + return self.impl_trait_ty_to_ty(did, lifetimes); + } + } + } + } + let item_segment = path.segments.split_last().unwrap(); + self.prohibit_generics(item_segment.1); + let substs = self.ast_path_substs_for_ty(span, did, item_segment.0); + self.normalize_ty( + span, + tcx.mk_anon(did, substs), + ) + } Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) | Def::TyForeign(did) => { assert_eq!(opt_self_ty, None); @@ -1095,11 +1115,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { hir::TyStr => tcx.mk_str() } } - Def::Existential(exist_ty_did) => { - assert!(exist_ty_did.is_local()); - let lifetimes = &path.segments[0].args.as_ref().unwrap().args; - self.impl_trait_ty_to_ty(exist_ty_did, lifetimes) - } Def::Err => { self.set_tainted_by_errors(); return self.tcx().types.err; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index bee866db9e467..301072778d094 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1332,6 +1332,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { match self.mode { Mode::MethodCall => item.method_has_self_argument, Mode::Path => match item.kind { + ty::AssociatedKind::Existential | ty::AssociatedKind::Type => false, ty::AssociatedKind::Method | ty::AssociatedKind::Const => true }, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9f83f8a00b1f5..e74652ff93210 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1410,6 +1410,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let kind = match impl_item.node { hir::ImplItemKind::Const(..) => ty::AssociatedKind::Const, hir::ImplItemKind::Method(..) => ty::AssociatedKind::Method, + hir::ImplItemKind::Existential(..) => ty::AssociatedKind::Existential, hir::ImplItemKind::Type(_) => ty::AssociatedKind::Type }; @@ -1503,6 +1504,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, err.emit() } } + hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(_) => { if ty_trait_item.kind == ty::AssociatedKind::Type { if ty_trait_item.defaultness.has_value() { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d876f41ce1307..df8323f85132b 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,11 +13,12 @@ use constrained_type_params::{identify_constrained_type_params, Parameter}; use hir::def_id::DefId; use rustc::traits::{self, ObligationCauseCode}; -use rustc::ty::{self, Lift, Ty, TyCtxt, GenericParamDefKind}; -use rustc::ty::subst::Substs; +use rustc::ty::{self, Lift, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; +use rustc::ty::subst::{Subst, Substs}; use rustc::ty::util::ExplicitSelf; use rustc::util::nodemap::{FxHashSet, FxHashMap}; use rustc::middle::lang_items; +use rustc::infer::anon_types::may_define_existential_type; use syntax::ast; use syntax::feature_gate::{self, GateIssue}; @@ -209,6 +210,10 @@ fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx.register_wf_obligation(ty, span, code.clone()); } } + ty::AssociatedKind::Existential => { + // FIXME(oli-obk) implement existential types in trait impls + unimplemented!() + } } implied_bounds @@ -282,7 +287,7 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - check_where_clauses(tcx, fcx, item.span, def_id); + check_where_clauses(tcx, fcx, item.span, def_id, None); vec![] // no implied bounds in a struct def'n }); @@ -291,7 +296,7 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { let trait_def_id = tcx.hir.local_def_id(item.id); for_item(tcx, item).with_fcx(|fcx, _| { - check_where_clauses(tcx, fcx, item.span, trait_def_id); + check_where_clauses(tcx, fcx, item.span, trait_def_id, None); vec![] }); } @@ -357,7 +362,7 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - check_where_clauses(tcx, fcx, item.span, item_def_id); + check_where_clauses(tcx, fcx, item.span, item_def_id, None); fcx.impl_implied_bounds(item_def_id, item.span) }); @@ -369,6 +374,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, def_id: DefId, + return_ty: Option>, ) { use ty::subst::Subst; use rustc::ty::TypeFoldable; @@ -482,7 +488,12 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( traits::Obligation::new(cause, fcx.param_env, pred) }); - let predicates = predicates.instantiate_identity(fcx.tcx); + let mut predicates = predicates.instantiate_identity(fcx.tcx); + + if let Some(return_ty) = return_ty { + predicates.predicates.extend(check_existential_types(tcx, fcx, def_id, span, return_ty)); + } + let predicates = fcx.normalize_associated_types_in(span, &predicates); debug!("check_where_clauses: predicates={:?}", predicates.predicates); @@ -521,7 +532,79 @@ fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, // FIXME(#25759) return types should not be implied bounds implied_bounds.push(sig.output()); - check_where_clauses(tcx, fcx, span, def_id); + check_where_clauses(tcx, fcx, span, def_id, Some(sig.output())); +} + +fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'gcx>, + fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, + fn_def_id: DefId, + span: Span, + ty: Ty<'tcx>, +) -> Vec> { + trace!("check_existential_types: {:?}, {:?}", ty, ty.sty); + let mut substituted_predicates = Vec::new(); + ty.fold_with(&mut ty::fold::BottomUpFolder { + tcx: fcx.tcx, + fldop: |ty| { + if let ty::TyAnon(def_id, substs) = ty.sty { + trace!("check_existential_types: anon_ty, {:?}, {:?}", def_id, substs); + 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) { + let generics = tcx.generics_of(def_id); + trace!("check_existential_types may define. Generics: {:#?}", generics); + for (subst, param) in substs.iter().zip(&generics.params) { + if let ty::subst::UnpackedKind::Type(ty) = subst.unpack() { + match ty.sty { + ty::TyParam(..) => {}, + // prevent `fn foo() -> Foo` from being defining + _ => { + tcx + .sess + .struct_span_err( + span, + "non-defining existential type use in defining scope", + ) + .span_note( + tcx.def_span(param.def_id), + &format!( + "used non-generic type {} for generic parameter", + ty, + ), + ) + .emit(); + return tcx.types.err; + }, + } // match ty + } // if let Type = subst + } // for (subst, param) + } // if may_define_existential_type + + // now register the bounds on the parameters of the existential type + // so the parameters given by the function need to fulfil them + // ```rust + // existential type Foo: 'static; + // fn foo() -> Foo { .. *} + // ``` + // becomes + // ```rust + // existential type Foo: 'static; + // fn foo() -> Foo { .. *} + // ``` + let predicates = tcx.predicates_of(def_id); + trace!("check_existential_types may define. adding predicates: {:#?}", predicates); + for &pred in predicates.predicates.iter() { + let substituted_pred = pred.subst(fcx.tcx, substs); + // Avoid duplication of predicates that contain no parameters, for example. + if !predicates.predicates.contains(&substituted_pred) { + substituted_predicates.push(substituted_pred); + } + } + } // if let TyAnon + ty + }, + }); + substituted_predicates } fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 3207ac44948f4..d82ad0d180bf5 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -17,9 +17,10 @@ use rustc::hir; use rustc::hir::def_id::{DefId, DefIndex}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::infer::InferCtxt; +use rustc::ty::subst::UnpackedKind; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::adjustment::{Adjust, Adjustment}; -use rustc::ty::fold::{TypeFoldable, TypeFolder}; +use rustc::ty::fold::{TypeFoldable, TypeFolder, BottomUpFolder}; use rustc::util::nodemap::DefIdSet; use syntax::ast; use syntax_pos::Span; @@ -388,11 +389,65 @@ 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 definition_ty = self.fcx.infer_anon_definition_from_instantiation( + 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() { + // prevent + // * `fn foo() -> Foo` + // * `fn foo() -> Foo` + // from being defining + + // Also replace all generic params with the ones from the existential type + // definition so + // ```rust + // existential type Foo: 'static; + // 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 { + tcx: self.tcx().global_tcx(), + fldop: |ty| { + // find a type parameter + if let ty::TyParam(..) = ty.sty { + // look it up in the substitution list + assert_eq!(anon_defn.substs.len(), generics.params.len()); + for (subst, param) in anon_defn.substs.iter().zip(&generics.params) { + if let UnpackedKind::Type(subst) = subst.unpack() { + if subst == ty { + // found it in the substitution list, replace with the + // parameter from the existential type + return self + .tcx() + .global_tcx() + .mk_ty_param(param.index, param.name); + } + } + } + self.tcx() + .sess + .struct_span_err( + span, + &format!( + "type parameter `{}` is part of concrete type but not used \ + in parameter list for existential type", + ty, + ), + ) + .emit(); + return self.tcx().types.err; + } + ty + }, + }); + } + let old = self.tables.concrete_existential_types.insert(def_id, definition_ty); if let Some(old) = old { if old != definition_ty { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4b628d6ffad75..ab81cb8788f9c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -269,6 +269,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemKind::Fn(.., ref generics, _) | ItemKind::Impl(_, _, _, ref generics, ..) | ItemKind::Ty(_, ref generics) | + ItemKind::Existential(ExistTy { ref generics, impl_trait_fn: None, ..}) | ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) => generics, @@ -419,7 +420,11 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { convert_variant_ctor(tcx, struct_def.id()); } }, - hir::ItemKind::Existential(..) => {} + + // Desugared from `impl Trait` -> visited by the function's return type + hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(_), .. }) => {} + + hir::ItemKind::Existential(..) | hir::ItemKind::Ty(..) | hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | @@ -1002,6 +1007,13 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } +fn report_assoc_ty_on_inherent_impl<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + span: Span, +) { + span_err!(tcx.sess, span, E0202, "associated types are not allowed in inherent impls"); +} + fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { @@ -1034,10 +1046,16 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.mk_fn_def(def_id, substs) } ImplItemKind::Const(ref ty, _) => icx.to_ty(ty), + ImplItemKind::Existential(ref _bounds) => { + if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() { + report_assoc_ty_on_inherent_impl(tcx, item.span); + } + // FIXME(oli-obk) implement existential types in trait impls + unimplemented!() + } ImplItemKind::Type(ref ty) => { if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() { - span_err!(tcx.sess, item.span, E0202, - "associated types are not allowed in inherent impls"); + report_assoc_ty_on_inherent_impl(tcx, item.span); } icx.to_ty(ty) @@ -1062,8 +1080,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let substs = Substs::identity_for_item(tcx, def_id); tcx.mk_adt(def, substs) } - // this is only reachable once we have named existential types - ItemKind::Existential(hir::ExistTy { impl_trait_fn: None, .. }) => unimplemented!(), + ItemKind::Existential(hir::ExistTy { impl_trait_fn: None, .. }) => { + find_existential_constraints(tcx, def_id) + }, // existential types desugared from impl Trait ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(owner), .. }) => { tcx.typeck_tables_of(owner).concrete_existential_types[&def_id] @@ -1153,6 +1172,95 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn find_existential_constraints<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, +) -> ty::Ty<'tcx> { + use rustc::hir::map::*; + use rustc::hir::*; + + struct ConstraintLocator<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + found: Option<(Span, ty::Ty<'tcx>)>, + } + impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> { + fn check(&mut self, node_id: ast::NodeId) { + let def_id = self.tcx.hir.local_def_id(node_id); + // don't try to check items that cannot possibly constrain the type + if !self.tcx.has_typeck_tables(def_id) { + return; + } + let ty = self + .tcx + .typeck_tables_of(def_id) + .concrete_existential_types + .get(&self.def_id) + .cloned(); + if let Some(ty) = ty { + // FIXME(oli-obk): trace the actual span from inference to improve errors + let span = self.tcx.def_span(def_id); + if let Some((prev_span, prev_ty)) = self.found { + if ty != prev_ty { + // found different concrete types for the existential type + let mut err = self.tcx.sess.struct_span_err( + span, + "defining existential type use differs from previous", + ); + err.span_note(prev_span, "previous use here"); + err.emit(); + } + } else { + self.found = Some((span, ty)); + } + } + } + } + impl<'a, 'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { + intravisit::NestedVisitorMap::All(&self.tcx.hir) + } + fn visit_item(&mut self, it: &'tcx Item) { + // the existential type itself or its children are not within its reveal scope + if self.tcx.hir.local_def_id(it.id) != self.def_id { + self.check(it.id); + intravisit::walk_item(self, it); + } + } + fn visit_impl_item(&mut self, it: &'tcx ImplItem) { + // the existential type itself or its children are not within its reveal scope + if self.tcx.hir.local_def_id(it.id) != self.def_id { + self.check(it.id); + intravisit::walk_impl_item(self, it); + } + } + fn visit_trait_item(&mut self, it: &'tcx TraitItem) { + self.check(it.id); + intravisit::walk_trait_item(self, it); + } + } + let mut locator = ConstraintLocator { def_id, tcx, found: None }; + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + let parent = tcx.hir.get_parent(node_id); + if parent == ast::CRATE_NODE_ID { + intravisit::walk_crate(&mut locator, tcx.hir.krate()); + } else { + match tcx.hir.get(parent) { + NodeItem(ref it) => intravisit::walk_item(&mut locator, it), + NodeImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it), + other => bug!("{:?} is not a valid parent of an existential type item", other), + } + } + match locator.found { + Some((_, ty)) => ty, + None => { + let span = tcx.def_span(def_id); + tcx.sess.span_err(span, "could not find defining uses"); + tcx.types.err + } + } +} + fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig<'tcx> { @@ -1366,6 +1474,9 @@ fn explicit_predicates_of<'a, 'tcx>( let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); + + let mut predicates = vec![]; + let ast_generics = match node { NodeTraitItem(item) => { &item.generics @@ -1391,23 +1502,28 @@ fn explicit_predicates_of<'a, 'tcx>( is_trait = Some((ty::TraitRef::identity(tcx, def_id), items)); generics } - ItemKind::Existential(ref exist_ty) => { + ItemKind::Existential(ExistTy { ref bounds, impl_trait_fn, ref generics }) => { let substs = Substs::identity_for_item(tcx, def_id); let anon_ty = tcx.mk_anon(def_id, substs); // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`. let bounds = compute_bounds(&icx, anon_ty, - &exist_ty.bounds, + bounds, SizedByDefault::Yes, tcx.def_span(def_id)); - let predicates = bounds.predicates(tcx, anon_ty); - - return ty::GenericPredicates { - parent: None, - predicates: predicates - }; + if impl_trait_fn.is_some() { + // impl Trait + return ty::GenericPredicates { + parent: None, + predicates: bounds.predicates(tcx, anon_ty), + }; + } else { + // named existential types + predicates.extend(bounds.predicates(tcx, anon_ty)); + generics + } } _ => &no_generics, @@ -1429,8 +1545,6 @@ fn explicit_predicates_of<'a, 'tcx>( let parent_count = generics.parent_count as u32; let has_own_self = generics.has_self && parent_count == 0; - let mut predicates = vec![]; - // Below we'll consider the bounds on the type parameters (including `Self`) // and the explicit where-clauses, but to get the full set of predicates // on a trait we need to add in the supertrait bounds and bounds found on diff --git a/src/librustc_typeck/namespace.rs b/src/librustc_typeck/namespace.rs index 6f0e46b3afee1..690bf1c550c0e 100644 --- a/src/librustc_typeck/namespace.rs +++ b/src/librustc_typeck/namespace.rs @@ -21,6 +21,7 @@ pub enum Namespace { impl From for Namespace { fn from(a_kind: ty::AssociatedKind) -> Self { match a_kind { + ty::AssociatedKind::Existential | ty::AssociatedKind::Type => Namespace::Type, ty::AssociatedKind::Const | ty::AssociatedKind::Method => Namespace::Value, @@ -31,6 +32,7 @@ impl From for Namespace { impl<'a> From <&'a hir::ImplItemKind> for Namespace { fn from(impl_kind: &'a hir::ImplItemKind) -> Self { match *impl_kind { + hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(..) => Namespace::Type, hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) => Namespace::Value, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2bf1f6e553f3d..cf4eec97d8cd7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -512,6 +512,7 @@ pub enum ItemEnum { FunctionItem(Function), ModuleItem(Module), TypedefItem(Typedef, bool /* is associated type */), + ExistentialItem(Existential, bool /* is associated type */), StaticItem(Static), ConstantItem(Constant), TraitItem(Trait), @@ -545,6 +546,7 @@ impl ItemEnum { ItemEnum::EnumItem(ref e) => &e.generics, ItemEnum::FunctionItem(ref f) => &f.generics, ItemEnum::TypedefItem(ref t, _) => &t.generics, + ItemEnum::ExistentialItem(ref t, _) => &t.generics, ItemEnum::TraitItem(ref t) => &t.generics, ItemEnum::ImplItem(ref i) => &i.generics, ItemEnum::TyMethodItem(ref i) => &i.generics, @@ -596,6 +598,7 @@ impl Clean for doctree::Module { items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); items.extend(self.typedefs.iter().map(|x| x.clean(cx))); + items.extend(self.existentials.iter().map(|x| x.clean(cx))); items.extend(self.statics.iter().map(|x| x.clean(cx))); items.extend(self.constants.iter().map(|x| x.clean(cx))); items.extend(self.traits.iter().map(|x| x.clean(cx))); @@ -2411,6 +2414,10 @@ impl Clean for hir::ImplItem { type_: ty.clean(cx), generics: Generics::default(), }, true), + hir::ImplItemKind::Existential(ref bounds) => ExistentialItem(Existential { + bounds: bounds.clean(cx), + generics: Generics::default(), + }, true), }; Item { name: Some(self.ident.name.clean(cx)), @@ -2554,6 +2561,7 @@ impl<'tcx> Clean for ty::AssociatedItem { }, true) } } + ty::AssociatedKind::Existential => unimplemented!(), }; let visibility = match self.container { @@ -3696,6 +3704,30 @@ impl Clean for doctree::Typedef { } } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct Existential { + pub bounds: Vec, + pub generics: Generics, +} + +impl Clean for doctree::Existential { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: Some(self.name.clean(cx)), + attrs: self.attrs.clean(cx), + source: self.whence.clean(cx), + def_id: cx.tcx.hir.local_def_id(self.id.clone()), + visibility: self.vis.clean(cx), + stability: self.stab.clean(cx), + deprecation: self.depr.clean(cx), + inner: ExistentialItem(Existential { + bounds: self.exist_ty.bounds.clean(cx), + generics: self.exist_ty.generics.clean(cx), + }, false), + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)] pub struct BareFunctionDecl { pub unsafety: hir::Unsafety, diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 6fd9ef234f423..591c660138aee 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -37,6 +37,7 @@ pub struct Module { pub mods: Vec, pub id: NodeId, pub typedefs: Vec, + pub existentials: Vec, pub statics: Vec, pub constants: Vec, pub traits: Vec, @@ -68,6 +69,7 @@ impl Module { fns : Vec::new(), mods : Vec::new(), typedefs : Vec::new(), + existentials: Vec::new(), statics : Vec::new(), constants : Vec::new(), traits : Vec::new(), @@ -167,6 +169,17 @@ pub struct Typedef { pub depr: Option, } +pub struct Existential { + pub exist_ty: hir::ExistTy, + pub name: Name, + pub id: ast::NodeId, + pub attrs: hir::HirVec, + pub whence: Span, + pub vis: hir::Visibility, + pub stab: Option, + pub depr: Option, +} + #[derive(Debug)] pub struct Static { pub type_: P, diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 9b8ada1f6e6b2..a5131e327e08e 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -43,6 +43,7 @@ pub enum ItemType { Union = 19, ForeignType = 20, Keyword = 21, + Existential = 22, } @@ -70,6 +71,7 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::EnumItem(..) => ItemType::Enum, clean::FunctionItem(..) => ItemType::Function, clean::TypedefItem(..) => ItemType::Typedef, + clean::ExistentialItem(..) => ItemType::Existential, clean::StaticItem(..) => ItemType::Static, clean::ConstantItem(..) => ItemType::Constant, clean::TraitItem(..) => ItemType::Trait, @@ -135,6 +137,7 @@ impl ItemType { ItemType::AssociatedConst => "associatedconstant", ItemType::ForeignType => "foreigntype", ItemType::Keyword => "keyword", + ItemType::Existential => "existential", } } @@ -148,6 +151,7 @@ impl ItemType { ItemType::Trait | ItemType::Primitive | ItemType::AssociatedType | + ItemType::Existential | ItemType::ForeignType => NameSpace::Type, ItemType::ExternCrate | diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 41c08dbf4ab65..928d7d38351f8 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1570,6 +1570,7 @@ struct AllTypes { macros: HashSet, functions: HashSet, typedefs: HashSet, + existentials: HashSet, statics: HashSet, constants: HashSet, keywords: HashSet, @@ -1586,6 +1587,7 @@ impl AllTypes { macros: HashSet::with_capacity(100), functions: HashSet::with_capacity(100), typedefs: HashSet::with_capacity(100), + existentials: HashSet::with_capacity(100), statics: HashSet::with_capacity(100), constants: HashSet::with_capacity(100), keywords: HashSet::with_capacity(100), @@ -1607,6 +1609,7 @@ impl AllTypes { ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)), ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)), ItemType::Typedef => self.typedefs.insert(ItemEntry::new(new_url, name)), + ItemType::Existential => self.existentials.insert(ItemEntry::new(new_url, name)), ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)), ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)), _ => true, @@ -1650,6 +1653,7 @@ impl fmt::Display for AllTypes { print_entries(f, &self.macros, "Macros", "macros")?; print_entries(f, &self.functions, "Functions", "functions")?; print_entries(f, &self.typedefs, "Typedefs", "typedefs")?; + print_entries(f, &self.existentials, "Existentials", "existentials")?; print_entries(f, &self.statics, "Statics", "statics")?; print_entries(f, &self.constants, "Constants", "constants") } @@ -4400,6 +4404,7 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { ItemType::AssociatedConst => ("associated-consts", "Associated Constants"), ItemType::ForeignType => ("foreign-types", "Foreign Types"), ItemType::Keyword => ("keywords", "Keywords"), + ItemType::Existential => ("existentials", "Existentials"), } } diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index fe116a22eccbf..699ee25436a10 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -84,6 +84,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { return ret; } // These items can all get re-exported + clean::ExistentialItem(..) | clean::TypedefItem(..) | clean::StaticItem(..) | clean::StructItem(..) | clean::EnumItem(..) | clean::TraitItem(..) | clean::FunctionItem(..) | diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 875ba111ec002..267b70009482f 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -439,6 +439,19 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { }; om.typedefs.push(t); }, + hir::ItemKind::Existential(ref exist_ty) => { + let t = Existential { + exist_ty: exist_ty.clone(), + name, + id: item.id, + attrs: item.attrs.clone(), + whence: item.span, + vis: item.vis.clone(), + stab: self.stability(item.id), + depr: self.deprecation(item.id), + }; + om.existentials.push(t); + }, hir::ItemKind::Static(ref ty, ref mut_, ref exp) => { let s = Static { type_: ty.clone(), @@ -523,9 +536,6 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { om.impls.push(i); } }, - hir::ItemKind::Existential(_) => { - // FIXME(oli-obk): actually generate docs for real existential items - } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index bcdad92bc32e7..1b6b47f5489d7 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1394,6 +1394,7 @@ pub enum ImplItemKind { Const(P, P), Method(MethodSig, P), Type(P), + Existential(GenericBounds), Macro(Mac), } @@ -2132,6 +2133,10 @@ pub enum ItemKind { /// /// E.g. `type Foo = Bar;` Ty(P, Generics), + /// An existential type declaration (`existential type`). + /// + /// E.g. `existential type Foo: Bar + Boo;` + Existential(GenericBounds, Generics), /// An enum definition (`enum` or `pub enum`). /// /// E.g. `enum Foo { C, D }` @@ -2183,6 +2188,7 @@ impl ItemKind { ItemKind::ForeignMod(..) => "foreign module", ItemKind::GlobalAsm(..) => "global asm", ItemKind::Ty(..) => "type alias", + ItemKind::Existential(..) => "existential type", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1a73096505f45..aef6b8ba5a89c 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -419,6 +419,9 @@ declare_features! ( // Allows macro invocations in `extern {}` blocks (active, macros_in_extern, "1.27.0", Some(49476), None), + // `existential type` + (active, existential_type, "1.28.0", Some(34511), None), + // unstable #[target_feature] directives (active, arm_target_feature, "1.27.0", Some(44839), None), (active, aarch64_target_feature, "1.27.0", Some(44839), None), @@ -1643,6 +1646,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, decl_macro, i.span, msg); } + ast::ItemKind::Existential(..) => { + gate_feature_post!( + &self, + existential_type, + i.span, + "existential types are unstable" + ); + } + _ => {} } @@ -1842,6 +1854,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable"); } } + ast::ImplItemKind::Existential(..) => { + gate_feature_post!( + &self, + existential_type, + ii.span, + "existential types are unstable" + ); + } + ast::ImplItemKind::Type(_) if !ii.generics.params.is_empty() => { gate_feature_post!(&self, generic_associated_types, ii.span, "generic associated types are unstable"); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d9d3febc4fe4d..9d5982c1e2861 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -912,6 +912,10 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::Ty(t, generics) => { ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics)) } + ItemKind::Existential(bounds, generics) => ItemKind::Existential( + folder.fold_bounds(bounds), + folder.fold_generics(generics), + ), ItemKind::Enum(enum_definition, generics) => { let generics = folder.fold_generics(generics); let variants = enum_definition.variants.move_map(|x| folder.fold_variant(x)); @@ -1002,6 +1006,9 @@ pub fn noop_fold_impl_item(i: ImplItem, folder: &mut T) folder.fold_block(body)) } ast::ImplItemKind::Type(ty) => ast::ImplItemKind::Type(folder.fold_ty(ty)), + ast::ImplItemKind::Existential(bounds) => { + ast::ImplItemKind::Existential(folder.fold_bounds(bounds)) + }, ast::ImplItemKind::Macro(mac) => ast::ImplItemKind::Macro(folder.fold_mac(mac)) }, span: folder.new_span(i.span), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 62bb5fbd04f7b..2eaa56ebeb826 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -63,6 +63,15 @@ use std::mem; use std::path::{self, Path, PathBuf}; use std::slice; +#[derive(Debug)] +/// Whether the type alias or associated type is a concrete type or an existential type +pub enum AliasKind { + /// Just a new name for the same type + Weak(P), + /// Only trait impls of the type will be usable, not the actual type itself + Existential(GenericBounds), +} + bitflags! { struct Restrictions: u8 { const STMT_EXPR = 1 << 0; @@ -5502,16 +5511,13 @@ impl<'a> Parser<'a> { let lo = self.span; let vis = self.parse_visibility(false)?; let defaultness = self.parse_defaultness(); - let (name, node, generics) = if self.eat_keyword(keywords::Type) { - // This parses the grammar: - // ImplItemAssocTy = Ident ["<"...">"] ["where" ...] "=" Ty ";" - let name = self.parse_ident()?; - let mut generics = self.parse_generics()?; - generics.where_clause = self.parse_where_clause()?; - self.expect(&token::Eq)?; - let typ = self.parse_ty()?; - self.expect(&token::Semi)?; - (name, ast::ImplItemKind::Type(typ), generics) + let (name, node, generics) = if let Some(type_) = self.eat_type() { + let (name, alias, generics) = type_?; + let kind = match alias { + AliasKind::Weak(typ) => ast::ImplItemKind::Type(typ), + AliasKind::Existential(bounds) => ast::ImplItemKind::Existential(bounds), + }; + (name, kind, generics) } else if self.is_const_item() { // This parses the grammar: // ImplItemConst = "const" Ident ":" Ty "=" Expr ";" @@ -6563,14 +6569,43 @@ impl<'a> Parser<'a> { } /// Parse type Foo = Bar; - fn parse_item_type(&mut self) -> PResult<'a, ItemInfo> { + /// or + /// existential type Foo: Bar; + /// or + /// return None without modifying the parser state + fn eat_type(&mut self) -> Option> { + // This parses the grammar: + // Ident ["<"...">"] ["where" ...] ("=" | ":") Ty ";" + if self.check_keyword(keywords::Type) || + self.check_keyword(keywords::Existential) && + self.look_ahead(1, |t| t.is_keyword(keywords::Type)) { + let existential = self.eat_keyword(keywords::Existential); + assert!(self.eat_keyword(keywords::Type)); + Some(self.parse_existential_or_alias(existential)) + } else { + None + } + } + + /// Parse type alias or existential type + fn parse_existential_or_alias( + &mut self, + existential: bool, + ) -> PResult<'a, (Ident, AliasKind, ast::Generics)> { let ident = self.parse_ident()?; let mut tps = self.parse_generics()?; tps.where_clause = self.parse_where_clause()?; - self.expect(&token::Eq)?; - let ty = self.parse_ty()?; + let alias = if existential { + self.expect(&token::Colon)?; + let bounds = self.parse_generic_bounds()?; + AliasKind::Existential(bounds) + } else { + self.expect(&token::Eq)?; + let ty = self.parse_ty()?; + AliasKind::Weak(ty) + }; self.expect(&token::Semi)?; - Ok((ident, ItemKind::Ty(ty, tps), None)) + Ok((ident, alias, tps)) } /// Parse the part of an "enum" decl following the '{' @@ -6926,15 +6961,19 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.eat_keyword(keywords::Type) { + if let Some(type_) = self.eat_type() { + let (ident, alias, generics) = type_?; // TYPE ITEM - let (ident, item_, extra_attrs) = self.parse_item_type()?; + let item_ = match alias { + AliasKind::Weak(ty) => ItemKind::Ty(ty, generics), + AliasKind::Existential(bounds) => ItemKind::Existential(bounds, generics), + }; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, - maybe_append(attrs, extra_attrs)); + attrs); return Ok(Some(item)); } if self.eat_keyword(keywords::Enum) { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b0a9003a45620..de68780ef2ca2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1280,9 +1280,7 @@ impl<'a> State<'a> { self.end()?; } ast::ItemKind::Ty(ref ty, ref generics) => { - self.ibox(INDENT_UNIT)?; - self.ibox(0)?; - self.word_nbsp(&visibility_qualified(&item.vis, "type"))?; + self.head(&visibility_qualified(&item.vis, "type"))?; self.print_ident(item.ident)?; self.print_generic_params(&generics.params)?; self.end()?; // end the inner ibox @@ -1294,6 +1292,18 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer ibox } + ast::ItemKind::Existential(ref bounds, ref generics) => { + self.head(&visibility_qualified(&item.vis, "existential type"))?; + self.print_ident(item.ident)?; + self.print_generic_params(&generics.params)?; + self.end()?; // end the inner ibox + + self.print_where_clause(&generics.where_clause)?; + self.s.space()?; + self.print_type_bounds(":", bounds)?; + self.s.word(";")?; + self.end()?; // end the outer ibox + } ast::ItemKind::Enum(ref enum_definition, ref params) => { self.print_enum_def( enum_definition, @@ -1501,8 +1511,8 @@ impl<'a> State<'a> { } } - pub fn print_defaultness(&mut self, defatulness: ast::Defaultness) -> io::Result<()> { - if let ast::Defaultness::Default = defatulness { + pub fn print_defaultness(&mut self, defaultness: ast::Defaultness) -> io::Result<()> { + if let ast::Defaultness::Default = defaultness { try!(self.word_nbsp("default")); } Ok(()) @@ -1650,6 +1660,10 @@ impl<'a> State<'a> { ast::ImplItemKind::Type(ref ty) => { self.print_associated_type(ii.ident, None, Some(ty))?; } + ast::ImplItemKind::Existential(ref bounds) => { + self.word_space("existential")?; + self.print_associated_type(ii.ident, Some(bounds), None)?; + } ast::ImplItemKind::Macro(ref mac) => { self.print_mac(mac)?; match mac.node.delim { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9211a2383b696..51be129737e56 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -252,6 +252,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_ty(typ); visitor.visit_generics(type_parameters) } + ItemKind::Existential(ref bounds, ref type_parameters) => { + walk_list!(visitor, visit_param_bound, bounds); + visitor.visit_generics(type_parameters) + } ItemKind::Enum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) @@ -600,6 +604,9 @@ pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, impl_item: &'a ImplIt ImplItemKind::Type(ref ty) => { visitor.visit_ty(ty); } + ImplItemKind::Existential(ref bounds) => { + walk_list!(visitor, visit_param_bound, bounds); + } ImplItemKind::Macro(ref mac) => { visitor.visit_mac(mac); } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 9a0c92f679366..62f22475e7de7 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -426,6 +426,7 @@ declare_keywords! { (56, Default, "default") (57, Dyn, "dyn") (58, Union, "union") + (59, Existential, "existential") } impl Symbol { diff --git a/src/test/parse-fail/issue-20711-2.rs b/src/test/parse-fail/issue-20711-2.rs index 05df16d21d85b..d0836d4af9737 100644 --- a/src/test/parse-fail/issue-20711-2.rs +++ b/src/test/parse-fail/issue-20711-2.rs @@ -9,6 +9,7 @@ // except according to those terms. // compile-flags: -Z parse-only +// ignore-tidy-linelength struct Foo; @@ -16,6 +17,6 @@ impl Foo { fn foo() {} #[stable(feature = "rust1", since = "1.0.0")] -} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or +} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, or fn main() {} diff --git a/src/test/parse-fail/issue-20711.rs b/src/test/parse-fail/issue-20711.rs index f30e20ad7dbdb..d944224798852 100644 --- a/src/test/parse-fail/issue-20711.rs +++ b/src/test/parse-fail/issue-20711.rs @@ -9,11 +9,12 @@ // except according to those terms. // compile-flags: -Z parse-only +// ignore-tidy-linelength struct Foo; impl Foo { #[stable(feature = "rust1", since = "1.0.0")] -} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or +} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, or fn main() {} diff --git a/src/test/parse-fail/removed-syntax-static-fn.rs b/src/test/parse-fail/removed-syntax-static-fn.rs index fbc6848f372f5..4c0cd3358ddbd 100644 --- a/src/test/parse-fail/removed-syntax-static-fn.rs +++ b/src/test/parse-fail/removed-syntax-static-fn.rs @@ -9,10 +9,11 @@ // except according to those terms. // compile-flags: -Z parse-only +// ignore-tidy-linelength struct S; impl S { static fn f() {} } -//~^^ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, +//~^^ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, diff --git a/src/test/run-pass/existential_type.rs b/src/test/run-pass/existential_type.rs new file mode 100644 index 0000000000000..d2cecd83036ec --- /dev/null +++ b/src/test/run-pass/existential_type.rs @@ -0,0 +1,113 @@ +// 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() { + assert_eq!(foo().to_string(), "foo"); + assert_eq!(bar1().to_string(), "bar1"); + assert_eq!(bar2().to_string(), "bar2"); + let mut x = bar1(); + x = bar2(); + assert_eq!(boo::boo().to_string(), "boo"); + assert_eq!(my_iter(42u8).collect::>(), vec![42u8]); +} + +// single definition +existential type Foo: std::fmt::Display; + +fn foo() -> Foo { + "foo" +} + +// two definitions +existential type Bar: std::fmt::Display; + +fn bar1() -> Bar { + "bar1" +} + +fn bar2() -> Bar { + "bar2" +} + +// definition in submodule +existential type Boo: std::fmt::Display; + +mod boo { + pub fn boo() -> super::Boo { + "boo" + } +} + +existential type MyIter: Iterator; + +fn my_iter(t: T) -> MyIter { + std::iter::once(t) +} + +fn my_iter2(t: T) -> MyIter { + std::iter::once(t) +} + +// param names should not have an effect! +fn my_iter3(u: U) -> MyIter { + std::iter::once(u) +} + +// param position should not have an effect! +fn my_iter4(_: U, v: V) -> MyIter { + std::iter::once(v) +} + +// param names should not have an effect! +existential type MyOtherIter: Iterator; + +fn my_other_iter(u: U) -> MyOtherIter { + std::iter::once(u) +} + +trait Trait {} +existential type GenericBound: 'static; + +fn generic_bound(_: T) -> GenericBound { + unimplemented!() +} + +mod pass_through { + pub existential type Passthrough: 'static; + + fn define_passthrough(t: T) -> Passthrough { + t + } +} + +fn use_passthrough(x: pass_through::Passthrough) -> pass_through::Passthrough { + x +} + +existential type PartiallyDefined: 'static; + +// doesn't declare all PartiallyDefined for all possible `T`, but since it's the only +// function producing the value, noone can ever get a value that is problematic +fn partially_defined(_: T) -> PartiallyDefined { + 4u32 +} + +existential type PartiallyDefined2: 'static; + +fn partially_defined2(_: T) -> PartiallyDefined2 { + 4u32 +} + +// fully defines PartiallyDefine2 +fn partially_defined22(_: T) -> PartiallyDefined2 { + 4u32 +} diff --git a/src/test/ui/suggestions/as-ref.rs b/src/test/ui/as-ref.rs similarity index 100% rename from src/test/ui/suggestions/as-ref.rs rename to src/test/ui/as-ref.rs diff --git a/src/test/ui/suggestions/as-ref.stderr b/src/test/ui/as-ref.stderr similarity index 100% rename from src/test/ui/suggestions/as-ref.stderr rename to src/test/ui/as-ref.stderr diff --git a/src/test/ui/suggestions/auxiliary/m1.rs b/src/test/ui/auxiliary/m1.rs similarity index 100% rename from src/test/ui/suggestions/auxiliary/m1.rs rename to src/test/ui/auxiliary/m1.rs diff --git a/src/test/ui/suggestions/auxiliary/m2.rs b/src/test/ui/auxiliary/m2.rs similarity index 100% rename from src/test/ui/suggestions/auxiliary/m2.rs rename to src/test/ui/auxiliary/m2.rs diff --git a/src/test/ui/suggestions/auxiliary/macro-in-other-crate.rs b/src/test/ui/auxiliary/macro-in-other-crate.rs similarity index 100% rename from src/test/ui/suggestions/auxiliary/macro-in-other-crate.rs rename to src/test/ui/auxiliary/macro-in-other-crate.rs diff --git a/src/test/ui/suggestions/auxiliary/removing-extern-crate.rs b/src/test/ui/auxiliary/removing-extern-crate.rs similarity index 100% rename from src/test/ui/suggestions/auxiliary/removing-extern-crate.rs rename to src/test/ui/auxiliary/removing-extern-crate.rs diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.fixed b/src/test/ui/closure-immutable-outer-variable.fixed similarity index 100% rename from src/test/ui/suggestions/closure-immutable-outer-variable.fixed rename to src/test/ui/closure-immutable-outer-variable.fixed diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.nll.stderr b/src/test/ui/closure-immutable-outer-variable.nll.stderr similarity index 100% rename from src/test/ui/suggestions/closure-immutable-outer-variable.nll.stderr rename to src/test/ui/closure-immutable-outer-variable.nll.stderr diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.rs b/src/test/ui/closure-immutable-outer-variable.rs similarity index 100% rename from src/test/ui/suggestions/closure-immutable-outer-variable.rs rename to src/test/ui/closure-immutable-outer-variable.rs diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.rs.fixed b/src/test/ui/closure-immutable-outer-variable.rs.fixed similarity index 100% rename from src/test/ui/suggestions/closure-immutable-outer-variable.rs.fixed rename to src/test/ui/closure-immutable-outer-variable.rs.fixed diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.stderr b/src/test/ui/closure-immutable-outer-variable.stderr similarity index 100% rename from src/test/ui/suggestions/closure-immutable-outer-variable.stderr rename to src/test/ui/closure-immutable-outer-variable.stderr diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs b/src/test/ui/confuse-field-and-method/issue-18343.rs similarity index 100% rename from src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs rename to src/test/ui/confuse-field-and-method/issue-18343.rs diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr b/src/test/ui/confuse-field-and-method/issue-18343.stderr similarity index 100% rename from src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr rename to src/test/ui/confuse-field-and-method/issue-18343.stderr diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs b/src/test/ui/confuse-field-and-method/issue-2392.rs similarity index 100% rename from src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs rename to src/test/ui/confuse-field-and-method/issue-2392.rs diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr similarity index 100% rename from src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr rename to src/test/ui/confuse-field-and-method/issue-2392.stderr diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs b/src/test/ui/confuse-field-and-method/issue-32128.rs similarity index 100% rename from src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs rename to src/test/ui/confuse-field-and-method/issue-32128.rs diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr b/src/test/ui/confuse-field-and-method/issue-32128.stderr similarity index 100% rename from src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr rename to src/test/ui/confuse-field-and-method/issue-32128.stderr diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-33784.rs b/src/test/ui/confuse-field-and-method/issue-33784.rs similarity index 100% rename from src/test/ui/suggestions/confuse-field-and-method/issue-33784.rs rename to src/test/ui/confuse-field-and-method/issue-33784.rs diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr b/src/test/ui/confuse-field-and-method/issue-33784.stderr similarity index 100% rename from src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr rename to src/test/ui/confuse-field-and-method/issue-33784.stderr diff --git a/src/test/ui/suggestions/confuse-field-and-method/private-field.rs b/src/test/ui/confuse-field-and-method/private-field.rs similarity index 100% rename from src/test/ui/suggestions/confuse-field-and-method/private-field.rs rename to src/test/ui/confuse-field-and-method/private-field.rs diff --git a/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr b/src/test/ui/confuse-field-and-method/private-field.stderr similarity index 100% rename from src/test/ui/suggestions/confuse-field-and-method/private-field.stderr rename to src/test/ui/confuse-field-and-method/private-field.stderr diff --git a/src/test/ui/suggestions/const-type-mismatch.rs b/src/test/ui/const-type-mismatch.rs similarity index 100% rename from src/test/ui/suggestions/const-type-mismatch.rs rename to src/test/ui/const-type-mismatch.rs diff --git a/src/test/ui/suggestions/const-type-mismatch.stderr b/src/test/ui/const-type-mismatch.stderr similarity index 100% rename from src/test/ui/suggestions/const-type-mismatch.stderr rename to src/test/ui/const-type-mismatch.stderr diff --git a/src/test/ui/suggestions/conversion-methods.rs b/src/test/ui/conversion-methods.rs similarity index 100% rename from src/test/ui/suggestions/conversion-methods.rs rename to src/test/ui/conversion-methods.rs diff --git a/src/test/ui/suggestions/conversion-methods.stderr b/src/test/ui/conversion-methods.stderr similarity index 100% rename from src/test/ui/suggestions/conversion-methods.stderr rename to src/test/ui/conversion-methods.stderr diff --git a/src/test/ui/suggestions/dont-suggest-private-trait-method.rs b/src/test/ui/dont-suggest-private-trait-method.rs similarity index 100% rename from src/test/ui/suggestions/dont-suggest-private-trait-method.rs rename to src/test/ui/dont-suggest-private-trait-method.rs diff --git a/src/test/ui/suggestions/dont-suggest-private-trait-method.stderr b/src/test/ui/dont-suggest-private-trait-method.stderr similarity index 100% rename from src/test/ui/suggestions/dont-suggest-private-trait-method.stderr rename to src/test/ui/dont-suggest-private-trait-method.stderr diff --git a/src/test/ui/suggestions/dotdotdot-expr.rs b/src/test/ui/dotdotdot-expr.rs similarity index 100% rename from src/test/ui/suggestions/dotdotdot-expr.rs rename to src/test/ui/dotdotdot-expr.rs diff --git a/src/test/ui/suggestions/dotdotdot-expr.stderr b/src/test/ui/dotdotdot-expr.stderr similarity index 100% rename from src/test/ui/suggestions/dotdotdot-expr.stderr rename to src/test/ui/dotdotdot-expr.stderr diff --git a/src/test/ui/existential_type.nll.stderr b/src/test/ui/existential_type.nll.stderr new file mode 100644 index 0000000000000..90840bf205ca2 --- /dev/null +++ b/src/test/ui/existential_type.nll.stderr @@ -0,0 +1,111 @@ +error: defining existential type use differs from previous + --> $DIR/existential_type.rs:23:1 + | +LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous +LL | | 42i32 +LL | | } + | |_^ + | +note: previous use here + --> $DIR/existential_type.rs:19:1 + | +LL | / fn foo() -> Foo { +LL | | "" +LL | | } + | |_^ + +error[E0308]: mismatched types + --> $DIR/existential_type.rs:36:5 + | +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` + +error[E0308]: mismatched types + --> $DIR/existential_type.rs:50:23 + | +LL | let _: &str = bomp(); //~ ERROR mismatched types + | ^^^^^^ expected &str, found anonymized type + | + = note: expected type `&str` + found type `Boo` + +error[E0308]: mismatched types + --> $DIR/existential_type.rs:54:9 + | +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` + +error[E0277]: the trait bound `T: Trait` is not satisfied + --> $DIR/existential_type.rs:61:1 + | +LL | existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | + = help: consider adding a `where T: Trait` bound + = note: the return type of a function must have a statically known size + +warning: not reporting region error due to nll + --> $DIR/existential_type.rs:78:1 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/existential_type.rs:93:27 + | +LL | let _: &'static str = x; //~ mismatched types + | ^ expected reference, found anonymized type + | + = note: expected type `&'static str` + found type `NoReveal` + +error[E0605]: non-primitive cast: `NoReveal` as `&'static str` + --> $DIR/existential_type.rs:94:13 + | +LL | let _ = x as &'static str; //~ non-primitive cast + | ^^^^^^^^^^^^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + +error: could not find defining uses + --> $DIR/existential_type.rs:28:1 + | +LL | existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not find defining uses + --> $DIR/existential_type.rs:32:5 + | +LL | pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: defining existential type use differs from previous + --> $DIR/existential_type.rs:74:1 + | +LL | / fn my_iter2(t: T) -> MyIter { //~ ERROR defining existential type use differs from previous +LL | | Some(t).into_iter() +LL | | } + | |_^ + | +note: previous use here + --> $DIR/existential_type.rs:70:1 + | +LL | / fn my_iter(t: T) -> MyIter { +LL | | std::iter::once(t) +LL | | } + | |_^ + +error: aborting due to 10 previous errors + +Some errors occurred: E0277, E0308, E0605. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_type.rs b/src/test/ui/existential_type.rs new file mode 100644 index 0000000000000..6824d36204977 --- /dev/null +++ b/src/test/ui/existential_type.rs @@ -0,0 +1,95 @@ +// 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() {} + +// two definitions with different types +existential type Foo: std::fmt::Debug; + +fn foo() -> Foo { + "" +} + +fn bar() -> Foo { //~ ERROR defining existential type use differs from previous + 42i32 +} + +// declared but never defined +existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses + +mod boo { + // declared in module but not defined inside of it + pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses +} + +fn bomp() -> boo::Boo { + "" //~ ERROR mismatched types +} + +mod boo2 { + mod boo { + pub existential type Boo: ::std::fmt::Debug; + fn bomp() -> Boo { + "" + } + } + + // don't actually know the type here + + fn bomp2() { + let _: &str = bomp(); //~ ERROR mismatched types + } + + fn bomp() -> boo::Boo { + "" //~ ERROR mismatched types + } +} + +// generics + +trait Trait {} +existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` + +// no `Trait` bound +fn underconstrain(_: T) -> Underconstrained { + unimplemented!() +} + +existential type MyIter: Iterator; + +fn my_iter(t: T) -> MyIter { + std::iter::once(t) +} + +fn my_iter2(t: T) -> MyIter { //~ ERROR defining existential type use differs from previous + Some(t).into_iter() +} + +existential type WrongGeneric: 'static; +//~^ ERROR the parameter type `T` may not live long enough + +fn wrong_generic(t: T) -> WrongGeneric { + t +} + +// don't reveal the concrete type +existential type NoReveal: std::fmt::Debug; + +fn define_no_reveal() -> NoReveal { + "" +} + +fn no_reveal(x: NoReveal) { + let _: &'static str = x; //~ mismatched types + let _ = x as &'static str; //~ non-primitive cast +} diff --git a/src/test/ui/existential_type.stderr b/src/test/ui/existential_type.stderr new file mode 100644 index 0000000000000..3e7476448bf7f --- /dev/null +++ b/src/test/ui/existential_type.stderr @@ -0,0 +1,120 @@ +error: defining existential type use differs from previous + --> $DIR/existential_type.rs:23:1 + | +LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous +LL | | 42i32 +LL | | } + | |_^ + | +note: previous use here + --> $DIR/existential_type.rs:19:1 + | +LL | / fn foo() -> Foo { +LL | | "" +LL | | } + | |_^ + +error[E0308]: mismatched types + --> $DIR/existential_type.rs:36:5 + | +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` + +error[E0308]: mismatched types + --> $DIR/existential_type.rs:50:23 + | +LL | let _: &str = bomp(); //~ ERROR mismatched types + | ^^^^^^ expected &str, found anonymized type + | + = note: expected type `&str` + found type `Boo` + +error[E0308]: mismatched types + --> $DIR/existential_type.rs:54:9 + | +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` + +error[E0277]: the trait bound `T: Trait` is not satisfied + --> $DIR/existential_type.rs:61:1 + | +LL | existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | + = help: consider adding a `where T: Trait` bound + = note: the return type of a function must have a statically known size + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/existential_type.rs:78:1 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn wrong_generic(t: T) -> WrongGeneric { + | - help: consider adding an explicit lifetime bound `T: 'static`... + | +note: ...so that the type `T` will meet its required lifetime bounds + --> $DIR/existential_type.rs:78:1 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/existential_type.rs:93:27 + | +LL | let _: &'static str = x; //~ mismatched types + | ^ expected reference, found anonymized type + | + = note: expected type `&'static str` + found type `NoReveal` + +error[E0605]: non-primitive cast: `NoReveal` as `&'static str` + --> $DIR/existential_type.rs:94:13 + | +LL | let _ = x as &'static str; //~ non-primitive cast + | ^^^^^^^^^^^^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + +error: could not find defining uses + --> $DIR/existential_type.rs:28:1 + | +LL | existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: could not find defining uses + --> $DIR/existential_type.rs:32:5 + | +LL | pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: defining existential type use differs from previous + --> $DIR/existential_type.rs:74:1 + | +LL | / fn my_iter2(t: T) -> MyIter { //~ ERROR defining existential type use differs from previous +LL | | Some(t).into_iter() +LL | | } + | |_^ + | +note: previous use here + --> $DIR/existential_type.rs:70:1 + | +LL | / fn my_iter(t: T) -> MyIter { +LL | | std::iter::once(t) +LL | | } + | |_^ + +error: aborting due to 11 previous errors + +Some errors occurred: E0277, E0308, E0310, E0605. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_type2.rs b/src/test/ui/existential_type2.rs new file mode 100644 index 0000000000000..bffb6b5ee109c --- /dev/null +++ b/src/test/ui/existential_type2.rs @@ -0,0 +1,30 @@ +// 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 Underconstrained: 'static; +//~^ ERROR `U` doesn't implement `std::fmt::Debug` + +// not a defining use, because it doesn't define *all* possible generics +fn underconstrained(_: U) -> Underconstrained { + 5u32 +} + +existential type Underconstrained2: 'static; +//~^ ERROR `V` doesn't implement `std::fmt::Debug` + +// not a defining use, because it doesn't define *all* possible generics +fn underconstrained2(_: U, _: V) -> Underconstrained2 { + 5u32 +} diff --git a/src/test/ui/existential_type2.stderr b/src/test/ui/existential_type2.stderr new file mode 100644 index 0000000000000..53003a4f05d12 --- /dev/null +++ b/src/test/ui/existential_type2.stderr @@ -0,0 +1,23 @@ +error[E0277]: `U` doesn't implement `std::fmt::Debug` + --> $DIR/existential_type2.rs:16:1 + | +LL | existential type Underconstrained: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `std::fmt::Debug` is not implemented for `U` + = help: consider adding a `where U: std::fmt::Debug` bound + = note: the return type of a function must have a statically known size + +error[E0277]: `V` doesn't implement `std::fmt::Debug` + --> $DIR/existential_type2.rs:24:1 + | +LL | existential type Underconstrained2: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `std::fmt::Debug` is not implemented for `V` + = help: consider adding a `where V: std::fmt::Debug` bound + = note: the return type of a function must have a statically known size + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_type3.rs b/src/test/ui/existential_type3.rs new file mode 100644 index 0000000000000..b090cf26b8796 --- /dev/null +++ b/src/test/ui/existential_type3.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. + + +#![feature(existential_type)] + +fn main() {} + +existential type WrongGeneric: 'static; + +fn wrong_generic(_: U, v: V) -> WrongGeneric { +//~^ ERROR type parameter `V` is part of concrete type but not used in parameter list + v +} diff --git a/src/test/ui/existential_type3.stderr b/src/test/ui/existential_type3.stderr new file mode 100644 index 0000000000000..90800728d7cc6 --- /dev/null +++ b/src/test/ui/existential_type3.stderr @@ -0,0 +1,12 @@ +error: type parameter `V` is part of concrete type but not used in parameter list for existential type + --> $DIR/existential_type3.rs:18:73 + | +LL | fn wrong_generic(_: U, v: V) -> WrongGeneric { + | _________________________________________________________________________^ +LL | | //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list +LL | | v +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.nll.fixed b/src/test/ui/existential_type4.rs similarity index 56% rename from src/test/ui/suggestions/closure-immutable-outer-variable.nll.fixed rename to src/test/ui/existential_type4.rs index e162678460c6c..a4b74d6751bd6 100644 --- a/src/test/ui/suggestions/closure-immutable-outer-variable.nll.fixed +++ b/src/test/ui/existential_type4.rs @@ -1,4 +1,4 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,15 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// run-rustfix -// Point at the captured immutable outer variable +#![feature(existential_type)] -fn foo(mut f: Box) { - f(); -} +fn main() {} + +existential type Cmp: 'static; -fn main() { - let y = true; - foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable +// not a defining use, because it doesn't define *all* possible generics +fn cmp() -> Cmp { //~ ERROR non-defining existential type use in defining scope + 5u32 } diff --git a/src/test/ui/existential_type4.stderr b/src/test/ui/existential_type4.stderr new file mode 100644 index 0000000000000..b11988746eac6 --- /dev/null +++ b/src/test/ui/existential_type4.stderr @@ -0,0 +1,16 @@ +error: non-defining existential type use in defining scope + --> $DIR/existential_type4.rs:19:1 + | +LL | / fn cmp() -> Cmp { //~ ERROR non-defining existential type use in defining scope +LL | | 5u32 +LL | | } + | |_^ + | +note: used non-generic type u32 for generic parameter + --> $DIR/existential_type4.rs:16:22 + | +LL | existential type Cmp: 'static; + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/extern-crate-rename.rs b/src/test/ui/extern-crate-rename.rs similarity index 100% rename from src/test/ui/suggestions/extern-crate-rename.rs rename to src/test/ui/extern-crate-rename.rs diff --git a/src/test/ui/suggestions/extern-crate-rename.stderr b/src/test/ui/extern-crate-rename.stderr similarity index 100% rename from src/test/ui/suggestions/extern-crate-rename.stderr rename to src/test/ui/extern-crate-rename.stderr diff --git a/src/test/ui/feature-gate-existential-type.rs b/src/test/ui/feature-gate-existential-type.rs new file mode 100644 index 0000000000000..b35a391637737 --- /dev/null +++ b/src/test/ui/feature-gate-existential-type.rs @@ -0,0 +1,25 @@ +// Copyright 2015 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. + +// Check that existential types must be ungated to use the `existential` keyword + + + +existential type Foo: std::fmt::Debug; //~ ERROR existential types are unstable + +trait Bar { + type Baa: std::fmt::Debug; +} + +impl Bar for () { + existential type Baa: std::fmt::Debug; //~ ERROR existential types are unstable +} + +fn main() {} diff --git a/src/test/ui/feature-gate-existential-type.stderr b/src/test/ui/feature-gate-existential-type.stderr new file mode 100644 index 0000000000000..6db5fa2ce6b94 --- /dev/null +++ b/src/test/ui/feature-gate-existential-type.stderr @@ -0,0 +1,19 @@ +error[E0658]: existential types are unstable (see issue #34511) + --> $DIR/feature-gate-existential-type.rs:15:1 + | +LL | existential type Foo: std::fmt::Debug; //~ ERROR existential types are unstable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(existential_type)] to the crate attributes to enable + +error[E0658]: existential types are unstable (see issue #34511) + --> $DIR/feature-gate-existential-type.rs:22:5 + | +LL | existential type Baa: std::fmt::Debug; //~ ERROR existential types are unstable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(existential_type)] to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/suggestions/fn-closure-mutable-capture.nll.stderr b/src/test/ui/fn-closure-mutable-capture.nll.stderr similarity index 100% rename from src/test/ui/suggestions/fn-closure-mutable-capture.nll.stderr rename to src/test/ui/fn-closure-mutable-capture.nll.stderr diff --git a/src/test/ui/suggestions/fn-closure-mutable-capture.rs b/src/test/ui/fn-closure-mutable-capture.rs similarity index 100% rename from src/test/ui/suggestions/fn-closure-mutable-capture.rs rename to src/test/ui/fn-closure-mutable-capture.rs diff --git a/src/test/ui/suggestions/fn-closure-mutable-capture.stderr b/src/test/ui/fn-closure-mutable-capture.stderr similarity index 100% rename from src/test/ui/suggestions/fn-closure-mutable-capture.stderr rename to src/test/ui/fn-closure-mutable-capture.stderr diff --git a/src/test/ui/suggestions/for-c-in-str.rs b/src/test/ui/for-c-in-str.rs similarity index 100% rename from src/test/ui/suggestions/for-c-in-str.rs rename to src/test/ui/for-c-in-str.rs diff --git a/src/test/ui/suggestions/for-c-in-str.stderr b/src/test/ui/for-c-in-str.stderr similarity index 100% rename from src/test/ui/suggestions/for-c-in-str.stderr rename to src/test/ui/for-c-in-str.stderr diff --git a/src/test/ui/suggestions/issue-32354-suggest-import-rename.fixed b/src/test/ui/issue-32354-suggest-import-rename.fixed similarity index 100% rename from src/test/ui/suggestions/issue-32354-suggest-import-rename.fixed rename to src/test/ui/issue-32354-suggest-import-rename.fixed diff --git a/src/test/ui/suggestions/issue-32354-suggest-import-rename.rs b/src/test/ui/issue-32354-suggest-import-rename.rs similarity index 100% rename from src/test/ui/suggestions/issue-32354-suggest-import-rename.rs rename to src/test/ui/issue-32354-suggest-import-rename.rs diff --git a/src/test/ui/suggestions/issue-32354-suggest-import-rename.stderr b/src/test/ui/issue-32354-suggest-import-rename.stderr similarity index 100% rename from src/test/ui/suggestions/issue-32354-suggest-import-rename.stderr rename to src/test/ui/issue-32354-suggest-import-rename.stderr diff --git a/src/test/ui/suggestions/issue-43420-no-over-suggest.rs b/src/test/ui/issue-43420-no-over-suggest.rs similarity index 100% rename from src/test/ui/suggestions/issue-43420-no-over-suggest.rs rename to src/test/ui/issue-43420-no-over-suggest.rs diff --git a/src/test/ui/suggestions/issue-43420-no-over-suggest.stderr b/src/test/ui/issue-43420-no-over-suggest.stderr similarity index 100% rename from src/test/ui/suggestions/issue-43420-no-over-suggest.stderr rename to src/test/ui/issue-43420-no-over-suggest.stderr diff --git a/src/test/ui/suggestions/issue-45562.fixed b/src/test/ui/issue-45562.fixed similarity index 100% rename from src/test/ui/suggestions/issue-45562.fixed rename to src/test/ui/issue-45562.fixed diff --git a/src/test/ui/suggestions/issue-45562.rs b/src/test/ui/issue-45562.rs similarity index 100% rename from src/test/ui/suggestions/issue-45562.rs rename to src/test/ui/issue-45562.rs diff --git a/src/test/ui/suggestions/issue-45562.stderr b/src/test/ui/issue-45562.stderr similarity index 100% rename from src/test/ui/suggestions/issue-45562.stderr rename to src/test/ui/issue-45562.stderr diff --git a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed b/src/test/ui/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed similarity index 100% rename from src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed rename to src/test/ui/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed diff --git a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs b/src/test/ui/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs similarity index 100% rename from src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs rename to src/test/ui/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs diff --git a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr b/src/test/ui/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr similarity index 100% rename from src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr rename to src/test/ui/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr diff --git a/src/test/ui/suggestions/issue-46302.rs b/src/test/ui/issue-46302.rs similarity index 100% rename from src/test/ui/suggestions/issue-46302.rs rename to src/test/ui/issue-46302.rs diff --git a/src/test/ui/suggestions/issue-46302.stderr b/src/test/ui/issue-46302.stderr similarity index 100% rename from src/test/ui/suggestions/issue-46302.stderr rename to src/test/ui/issue-46302.stderr diff --git a/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.fixed b/src/test/ui/issue-46756-consider-borrowing-cast-or-binexpr.fixed similarity index 100% rename from src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.fixed rename to src/test/ui/issue-46756-consider-borrowing-cast-or-binexpr.fixed diff --git a/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.rs b/src/test/ui/issue-46756-consider-borrowing-cast-or-binexpr.rs similarity index 100% rename from src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.rs rename to src/test/ui/issue-46756-consider-borrowing-cast-or-binexpr.rs diff --git a/src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.stderr b/src/test/ui/issue-46756-consider-borrowing-cast-or-binexpr.stderr similarity index 100% rename from src/test/ui/suggestions/issue-46756-consider-borrowing-cast-or-binexpr.stderr rename to src/test/ui/issue-46756-consider-borrowing-cast-or-binexpr.stderr diff --git a/src/test/ui/suggestions/issue-48364.rs b/src/test/ui/issue-48364.rs similarity index 100% rename from src/test/ui/suggestions/issue-48364.rs rename to src/test/ui/issue-48364.rs diff --git a/src/test/ui/suggestions/issue-48364.stderr b/src/test/ui/issue-48364.stderr similarity index 100% rename from src/test/ui/suggestions/issue-48364.stderr rename to src/test/ui/issue-48364.stderr diff --git a/src/test/ui/suggestions/issue-51244.nll.stderr b/src/test/ui/issue-51244.nll.stderr similarity index 100% rename from src/test/ui/suggestions/issue-51244.nll.stderr rename to src/test/ui/issue-51244.nll.stderr diff --git a/src/test/ui/suggestions/issue-51244.rs b/src/test/ui/issue-51244.rs similarity index 100% rename from src/test/ui/suggestions/issue-51244.rs rename to src/test/ui/issue-51244.rs diff --git a/src/test/ui/suggestions/issue-51244.stderr b/src/test/ui/issue-51244.stderr similarity index 100% rename from src/test/ui/suggestions/issue-51244.stderr rename to src/test/ui/issue-51244.stderr diff --git a/src/test/ui/suggestions/issue-51515.rs b/src/test/ui/issue-51515.rs similarity index 100% rename from src/test/ui/suggestions/issue-51515.rs rename to src/test/ui/issue-51515.rs diff --git a/src/test/ui/suggestions/issue-51515.stderr b/src/test/ui/issue-51515.stderr similarity index 100% rename from src/test/ui/suggestions/issue-51515.stderr rename to src/test/ui/issue-51515.stderr diff --git a/src/test/ui/suggestions/issue-52049.nll.stderr b/src/test/ui/issue-52049.nll.stderr similarity index 100% rename from src/test/ui/suggestions/issue-52049.nll.stderr rename to src/test/ui/issue-52049.nll.stderr diff --git a/src/test/ui/suggestions/issue-52049.rs b/src/test/ui/issue-52049.rs similarity index 100% rename from src/test/ui/suggestions/issue-52049.rs rename to src/test/ui/issue-52049.rs diff --git a/src/test/ui/suggestions/issue-52049.stderr b/src/test/ui/issue-52049.stderr similarity index 100% rename from src/test/ui/suggestions/issue-52049.stderr rename to src/test/ui/issue-52049.stderr diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs b/src/test/ui/method-on-ambiguous-numeric-type.rs similarity index 100% rename from src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs rename to src/test/ui/method-on-ambiguous-numeric-type.rs diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr b/src/test/ui/method-on-ambiguous-numeric-type.stderr similarity index 100% rename from src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr rename to src/test/ui/method-on-ambiguous-numeric-type.stderr diff --git a/src/test/ui/suggestions/missing-comma-in-match.fixed b/src/test/ui/missing-comma-in-match.fixed similarity index 100% rename from src/test/ui/suggestions/missing-comma-in-match.fixed rename to src/test/ui/missing-comma-in-match.fixed diff --git a/src/test/ui/suggestions/missing-comma-in-match.rs b/src/test/ui/missing-comma-in-match.rs similarity index 100% rename from src/test/ui/suggestions/missing-comma-in-match.rs rename to src/test/ui/missing-comma-in-match.rs diff --git a/src/test/ui/suggestions/missing-comma-in-match.stderr b/src/test/ui/missing-comma-in-match.stderr similarity index 100% rename from src/test/ui/suggestions/missing-comma-in-match.stderr rename to src/test/ui/missing-comma-in-match.stderr diff --git a/src/test/ui/suggestions/numeric-cast-2.rs b/src/test/ui/numeric-cast-2.rs similarity index 100% rename from src/test/ui/suggestions/numeric-cast-2.rs rename to src/test/ui/numeric-cast-2.rs diff --git a/src/test/ui/suggestions/numeric-cast-2.stderr b/src/test/ui/numeric-cast-2.stderr similarity index 100% rename from src/test/ui/suggestions/numeric-cast-2.stderr rename to src/test/ui/numeric-cast-2.stderr diff --git a/src/test/ui/suggestions/numeric-cast.rs b/src/test/ui/numeric-cast.rs similarity index 100% rename from src/test/ui/suggestions/numeric-cast.rs rename to src/test/ui/numeric-cast.rs diff --git a/src/test/ui/suggestions/numeric-cast.stderr b/src/test/ui/numeric-cast.stderr similarity index 100% rename from src/test/ui/suggestions/numeric-cast.stderr rename to src/test/ui/numeric-cast.stderr diff --git a/src/test/ui/suggestions/placement-syntax.rs b/src/test/ui/placement-syntax.rs similarity index 100% rename from src/test/ui/suggestions/placement-syntax.rs rename to src/test/ui/placement-syntax.rs diff --git a/src/test/ui/suggestions/placement-syntax.stderr b/src/test/ui/placement-syntax.stderr similarity index 100% rename from src/test/ui/suggestions/placement-syntax.stderr rename to src/test/ui/placement-syntax.stderr diff --git a/src/test/ui/suggestions/pub-ident-fn-2.rs b/src/test/ui/pub-ident-fn-2.rs similarity index 100% rename from src/test/ui/suggestions/pub-ident-fn-2.rs rename to src/test/ui/pub-ident-fn-2.rs diff --git a/src/test/ui/suggestions/pub-ident-fn-2.stderr b/src/test/ui/pub-ident-fn-2.stderr similarity index 100% rename from src/test/ui/suggestions/pub-ident-fn-2.stderr rename to src/test/ui/pub-ident-fn-2.stderr diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct-2.rs b/src/test/ui/pub-ident-fn-or-struct-2.rs similarity index 100% rename from src/test/ui/suggestions/pub-ident-fn-or-struct-2.rs rename to src/test/ui/pub-ident-fn-or-struct-2.rs diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr b/src/test/ui/pub-ident-fn-or-struct-2.stderr similarity index 100% rename from src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr rename to src/test/ui/pub-ident-fn-or-struct-2.stderr diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct.rs b/src/test/ui/pub-ident-fn-or-struct.rs similarity index 100% rename from src/test/ui/suggestions/pub-ident-fn-or-struct.rs rename to src/test/ui/pub-ident-fn-or-struct.rs diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct.stderr b/src/test/ui/pub-ident-fn-or-struct.stderr similarity index 100% rename from src/test/ui/suggestions/pub-ident-fn-or-struct.stderr rename to src/test/ui/pub-ident-fn-or-struct.stderr diff --git a/src/test/ui/suggestions/pub-ident-fn.fixed b/src/test/ui/pub-ident-fn.fixed similarity index 100% rename from src/test/ui/suggestions/pub-ident-fn.fixed rename to src/test/ui/pub-ident-fn.fixed diff --git a/src/test/ui/suggestions/pub-ident-fn.rs b/src/test/ui/pub-ident-fn.rs similarity index 100% rename from src/test/ui/suggestions/pub-ident-fn.rs rename to src/test/ui/pub-ident-fn.rs diff --git a/src/test/ui/suggestions/pub-ident-fn.stderr b/src/test/ui/pub-ident-fn.stderr similarity index 100% rename from src/test/ui/suggestions/pub-ident-fn.stderr rename to src/test/ui/pub-ident-fn.stderr diff --git a/src/test/ui/suggestions/pub-ident-struct.rs b/src/test/ui/pub-ident-struct.rs similarity index 100% rename from src/test/ui/suggestions/pub-ident-struct.rs rename to src/test/ui/pub-ident-struct.rs diff --git a/src/test/ui/suggestions/pub-ident-struct.stderr b/src/test/ui/pub-ident-struct.stderr similarity index 100% rename from src/test/ui/suggestions/pub-ident-struct.stderr rename to src/test/ui/pub-ident-struct.stderr diff --git a/src/test/ui/suggestions/removing-extern-crate.fixed b/src/test/ui/removing-extern-crate.fixed similarity index 100% rename from src/test/ui/suggestions/removing-extern-crate.fixed rename to src/test/ui/removing-extern-crate.fixed diff --git a/src/test/ui/suggestions/removing-extern-crate.rs b/src/test/ui/removing-extern-crate.rs similarity index 100% rename from src/test/ui/suggestions/removing-extern-crate.rs rename to src/test/ui/removing-extern-crate.rs diff --git a/src/test/ui/suggestions/removing-extern-crate.stderr b/src/test/ui/removing-extern-crate.stderr similarity index 100% rename from src/test/ui/suggestions/removing-extern-crate.stderr rename to src/test/ui/removing-extern-crate.stderr diff --git a/src/test/ui/suggestions/repr.rs b/src/test/ui/repr.rs similarity index 100% rename from src/test/ui/suggestions/repr.rs rename to src/test/ui/repr.rs diff --git a/src/test/ui/suggestions/repr.stderr b/src/test/ui/repr.stderr similarity index 100% rename from src/test/ui/suggestions/repr.stderr rename to src/test/ui/repr.stderr diff --git a/src/test/ui/suggestions/return-type.rs b/src/test/ui/return-type.rs similarity index 100% rename from src/test/ui/suggestions/return-type.rs rename to src/test/ui/return-type.rs diff --git a/src/test/ui/suggestions/return-type.stderr b/src/test/ui/return-type.stderr similarity index 100% rename from src/test/ui/suggestions/return-type.stderr rename to src/test/ui/return-type.stderr diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr index 3dd2675646cde..6d18075ba37cf 100644 --- a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr +++ b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr @@ -1,11 +1,11 @@ -error: lifetime parameter `'b` only used once - --> $DIR/one-use-in-fn-argument-in-band.rs:19:22 +error: lifetime parameter `'a` only used once + --> $DIR/one-use-in-fn-argument-in-band.rs:19:10 | LL | fn a(x: &'a u32, y: &'b u32) { - | ^^ - | | - | this lifetime... - | ...is used only here + | ^^ + | | + | this lifetime... + | ...is used only here | note: lint level defined here --> $DIR/one-use-in-fn-argument-in-band.rs:12:9 @@ -13,14 +13,14 @@ note: lint level defined here LL | #![deny(single_use_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^ -error: lifetime parameter `'a` only used once - --> $DIR/one-use-in-fn-argument-in-band.rs:19:10 +error: lifetime parameter `'b` only used once + --> $DIR/one-use-in-fn-argument-in-band.rs:19:22 | LL | fn a(x: &'a u32, y: &'b u32) { - | ^^ - | | - | this lifetime... - | ...is used only here + | ^^ + | | + | this lifetime... + | ...is used only here error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/str-array-assignment.rs b/src/test/ui/str-array-assignment.rs similarity index 100% rename from src/test/ui/suggestions/str-array-assignment.rs rename to src/test/ui/str-array-assignment.rs diff --git a/src/test/ui/suggestions/str-array-assignment.stderr b/src/test/ui/str-array-assignment.stderr similarity index 100% rename from src/test/ui/suggestions/str-array-assignment.stderr rename to src/test/ui/str-array-assignment.stderr diff --git a/src/test/ui/suggestions/str-as-char.fixed b/src/test/ui/str-as-char.fixed similarity index 100% rename from src/test/ui/suggestions/str-as-char.fixed rename to src/test/ui/str-as-char.fixed diff --git a/src/test/ui/suggestions/str-as-char.rs b/src/test/ui/str-as-char.rs similarity index 100% rename from src/test/ui/suggestions/str-as-char.rs rename to src/test/ui/str-as-char.rs diff --git a/src/test/ui/suggestions/str-as-char.stderr b/src/test/ui/str-as-char.stderr similarity index 100% rename from src/test/ui/suggestions/str-as-char.stderr rename to src/test/ui/str-as-char.stderr diff --git a/src/test/ui/suggestions/suggest-labels.rs b/src/test/ui/suggest-labels.rs similarity index 100% rename from src/test/ui/suggestions/suggest-labels.rs rename to src/test/ui/suggest-labels.rs diff --git a/src/test/ui/suggestions/suggest-labels.stderr b/src/test/ui/suggest-labels.stderr similarity index 100% rename from src/test/ui/suggestions/suggest-labels.stderr rename to src/test/ui/suggest-labels.stderr diff --git a/src/test/ui/suggestions/suggest-methods.rs b/src/test/ui/suggest-methods.rs similarity index 100% rename from src/test/ui/suggestions/suggest-methods.rs rename to src/test/ui/suggest-methods.rs diff --git a/src/test/ui/suggestions/suggest-methods.stderr b/src/test/ui/suggest-methods.stderr similarity index 100% rename from src/test/ui/suggestions/suggest-methods.stderr rename to src/test/ui/suggest-methods.stderr diff --git a/src/test/ui/suggestions/suggest-ref-mut.rs b/src/test/ui/suggest-ref-mut.rs similarity index 100% rename from src/test/ui/suggestions/suggest-ref-mut.rs rename to src/test/ui/suggest-ref-mut.rs diff --git a/src/test/ui/suggestions/suggest-ref-mut.stderr b/src/test/ui/suggest-ref-mut.stderr similarity index 100% rename from src/test/ui/suggestions/suggest-ref-mut.stderr rename to src/test/ui/suggest-ref-mut.stderr diff --git a/src/test/ui/token/issue-41155.stderr b/src/test/ui/token/issue-41155.stderr index 84dbc7ffc2f8f..5c1aae29c2fdf 100644 --- a/src/test/ui/token/issue-41155.stderr +++ b/src/test/ui/token/issue-41155.stderr @@ -1,8 +1,8 @@ -error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}` +error: expected one of `(`, `async`, `const`, `default`, `existential`, `extern`, `fn`, `type`, or `unsafe`, found `}` --> $DIR/issue-41155.rs:13:1 | LL | pub - | - expected one of 8 possible tokens here + | - expected one of 9 possible tokens here LL | } //~ ERROR expected one of | ^ unexpected token diff --git a/src/test/ui/suggestions/try-on-option.rs b/src/test/ui/try-on-option.rs similarity index 100% rename from src/test/ui/suggestions/try-on-option.rs rename to src/test/ui/try-on-option.rs diff --git a/src/test/ui/suggestions/try-on-option.stderr b/src/test/ui/try-on-option.stderr similarity index 100% rename from src/test/ui/suggestions/try-on-option.stderr rename to src/test/ui/try-on-option.stderr diff --git a/src/test/ui/suggestions/try-operator-on-main.rs b/src/test/ui/try-operator-on-main.rs similarity index 100% rename from src/test/ui/suggestions/try-operator-on-main.rs rename to src/test/ui/try-operator-on-main.rs diff --git a/src/test/ui/suggestions/try-operator-on-main.stderr b/src/test/ui/try-operator-on-main.stderr similarity index 100% rename from src/test/ui/suggestions/try-operator-on-main.stderr rename to src/test/ui/try-operator-on-main.stderr diff --git a/src/test/ui/suggestions/tuple-float-index.fixed b/src/test/ui/tuple-float-index.fixed similarity index 100% rename from src/test/ui/suggestions/tuple-float-index.fixed rename to src/test/ui/tuple-float-index.fixed diff --git a/src/test/ui/suggestions/tuple-float-index.rs b/src/test/ui/tuple-float-index.rs similarity index 100% rename from src/test/ui/suggestions/tuple-float-index.rs rename to src/test/ui/tuple-float-index.rs diff --git a/src/test/ui/suggestions/tuple-float-index.stderr b/src/test/ui/tuple-float-index.stderr similarity index 100% rename from src/test/ui/suggestions/tuple-float-index.stderr rename to src/test/ui/tuple-float-index.stderr diff --git a/src/test/ui/suggestions/type-ascription-instead-of-initializer.rs b/src/test/ui/type-ascription-instead-of-initializer.rs similarity index 100% rename from src/test/ui/suggestions/type-ascription-instead-of-initializer.rs rename to src/test/ui/type-ascription-instead-of-initializer.rs diff --git a/src/test/ui/suggestions/type-ascription-instead-of-initializer.stderr b/src/test/ui/type-ascription-instead-of-initializer.stderr similarity index 100% rename from src/test/ui/suggestions/type-ascription-instead-of-initializer.stderr rename to src/test/ui/type-ascription-instead-of-initializer.stderr diff --git a/src/test/ui/suggestions/type-ascription-instead-of-statement-end.rs b/src/test/ui/type-ascription-instead-of-statement-end.rs similarity index 100% rename from src/test/ui/suggestions/type-ascription-instead-of-statement-end.rs rename to src/test/ui/type-ascription-instead-of-statement-end.rs diff --git a/src/test/ui/suggestions/type-ascription-instead-of-statement-end.stderr b/src/test/ui/type-ascription-instead-of-statement-end.stderr similarity index 100% rename from src/test/ui/suggestions/type-ascription-instead-of-statement-end.stderr rename to src/test/ui/type-ascription-instead-of-statement-end.stderr diff --git a/src/test/ui/suggestions/type-ascription-with-fn-call.rs b/src/test/ui/type-ascription-with-fn-call.rs similarity index 100% rename from src/test/ui/suggestions/type-ascription-with-fn-call.rs rename to src/test/ui/type-ascription-with-fn-call.rs diff --git a/src/test/ui/suggestions/type-ascription-with-fn-call.stderr b/src/test/ui/type-ascription-with-fn-call.stderr similarity index 100% rename from src/test/ui/suggestions/type-ascription-with-fn-call.stderr rename to src/test/ui/type-ascription-with-fn-call.stderr From 3e215a3c87362d386206d8cca55710d2d5032e18 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 11 Jul 2018 16:01:48 +0200 Subject: [PATCH 02/16] Typeck existential types properly --- src/librustc_typeck/check/mod.rs | 1 + src/test/ui/impl-trait/auto-trait-leak.rs | 2 + src/test/ui/impl-trait/auto-trait-leak.stderr | 56 ++++++++++++++++--- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e74652ff93210..e4a93b09e98e8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1309,6 +1309,7 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item hir::ItemKind::Union(..) => { check_union(tcx, it.id, it.span); } + hir::ItemKind::Existential(..) | hir::ItemKind::Ty(..) => { let def_id = tcx.hir.local_def_id(it.id); let pty_ty = tcx.type_of(def_id); diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index a594ee8aab42a..a241ba53461ff 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -23,7 +23,9 @@ fn main() { // return type, which can't depend on the obligation. fn cycle1() -> impl Clone { //~^ ERROR cycle detected + //~| ERROR cycle detected send(cycle2().clone()); + //~^ ERROR cannot be sent between threads safely Rc::new(Cell::new(5)) } diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 6681116f0f393..10711d1cd8cec 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -1,29 +1,67 @@ -error[E0391]: cycle detected when processing `cycle1` +error[E0391]: cycle detected when processing `cycle1::{{impl-Trait}}` + --> $DIR/auto-trait-leak.rs:24:16 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^ + | +note: ...which requires processing `cycle1`... --> $DIR/auto-trait-leak.rs:24:1 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... note: ...which requires processing `cycle2::{{impl-Trait}}`... - --> $DIR/auto-trait-leak.rs:31:16 + --> $DIR/auto-trait-leak.rs:33:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:31:1 + --> $DIR/auto-trait-leak.rs:33:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires processing `cycle1::{{impl-Trait}}`... + = note: ...which again requires processing `cycle1::{{impl-Trait}}`, completing the cycle + +error[E0391]: cycle detected when processing `cycle1::{{impl-Trait}}` --> $DIR/auto-trait-leak.rs:24:16 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ - = note: ...which again requires processing `cycle1`, completing the cycle -note: cycle used when type-checking all item bodies + | +note: ...which requires processing `cycle1`... + --> $DIR/auto-trait-leak.rs:24:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... +note: ...which requires processing `cycle2::{{impl-Trait}}`... + --> $DIR/auto-trait-leak.rs:33:16 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^ +note: ...which requires processing `cycle2`... + --> $DIR/auto-trait-leak.rs:33:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires processing `cycle1::{{impl-Trait}}`, completing the cycle + +error[E0277]: `std::rc::Rc` cannot be sent between threads safely + --> $DIR/auto-trait-leak.rs:27:5 + | +LL | send(cycle2().clone()); + | ^^^^ `std::rc::Rc` cannot be sent between threads safely + | + = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` + = note: required because it appears within the type `impl std::clone::Clone` +note: required by `send` + --> $DIR/auto-trait-leak.rs:16:1 + | +LL | fn send(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0391`. +Some errors occurred: E0277, E0391. +For more information about an error, try `rustc --explain E0277`. From 2ed1aca101d449bb24d607ffbe436511e999573d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 16 Jul 2018 10:46:27 +0200 Subject: [PATCH 03/16] Only check existential types, not the desugared impl Trait --- src/librustc_typeck/check/wfcheck.rs | 108 ++++++++++++++------------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index df8323f85132b..d2c9622199160 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -549,57 +549,65 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( fldop: |ty| { if let ty::TyAnon(def_id, substs) = ty.sty { trace!("check_existential_types: anon_ty, {:?}, {:?}", def_id, substs); - 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) { - let generics = tcx.generics_of(def_id); - trace!("check_existential_types may define. Generics: {:#?}", generics); - for (subst, param) in substs.iter().zip(&generics.params) { - if let ty::subst::UnpackedKind::Type(ty) = subst.unpack() { - match ty.sty { - ty::TyParam(..) => {}, - // prevent `fn foo() -> Foo` from being defining - _ => { - tcx - .sess - .struct_span_err( - span, - "non-defining existential type use in defining scope", - ) - .span_note( - tcx.def_span(param.def_id), - &format!( - "used non-generic type {} for generic parameter", - ty, - ), - ) - .emit(); - return tcx.types.err; - }, - } // match ty - } // if let Type = subst - } // for (subst, param) - } // if may_define_existential_type - - // now register the bounds on the parameters of the existential type - // so the parameters given by the function need to fulfil them - // ```rust - // existential type Foo: 'static; - // fn foo() -> Foo { .. *} - // ``` - // becomes - // ```rust - // existential type Foo: 'static; - // fn foo() -> Foo { .. *} - // ``` - let predicates = tcx.predicates_of(def_id); - trace!("check_existential_types may define. adding predicates: {:#?}", predicates); - for &pred in predicates.predicates.iter() { - let substituted_pred = pred.subst(fcx.tcx, substs); - // Avoid duplication of predicates that contain no parameters, for example. - if !predicates.predicates.contains(&substituted_pred) { - substituted_predicates.push(substituted_pred); + let generics = tcx.generics_of(def_id); + // only check named existential types + if generics.parent.is_none() { + 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); + for (subst, param) in substs.iter().zip(&generics.params) { + if let ty::subst::UnpackedKind::Type(ty) = subst.unpack() { + match ty.sty { + ty::TyParam(..) => {}, + // prevent `fn foo() -> Foo` from being defining + _ => { + tcx + .sess + .struct_span_err( + span, + "non-defining existential type use \ + in defining scope", + ) + .span_note( + tcx.def_span(param.def_id), + &format!( + "used non-generic type {} for \ + generic parameter", + ty, + ), + ) + .emit(); + return tcx.types.err; + }, + } // match ty + } // if let Type = subst + } // for (subst, param) + } // if may_define_existential_type + + // now register the bounds on the parameters of the existential type + // so the parameters given by the function need to fulfil them + // ```rust + // existential type Foo: 'static; + // fn foo() -> Foo { .. *} + // ``` + // becomes + // ```rust + // existential type Foo: 'static; + // fn foo() -> Foo { .. *} + // ``` + let predicates = tcx.predicates_of(def_id); + trace!( + "check_existential_types may define. adding predicates: {:#?}", + predicates, + ); + for &pred in predicates.predicates.iter() { + let substituted_pred = pred.subst(fcx.tcx, substs); + // Avoid duplication of predicates that contain no parameters, for example. + if !predicates.predicates.contains(&substituted_pred) { + substituted_predicates.push(substituted_pred); + } } - } + } // if is_named_existential_type } // if let TyAnon ty }, From 4e8cc76a91d22d060e0278be8f441533227a05fa Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 16 Jul 2018 10:57:31 +0200 Subject: [PATCH 04/16] Add test for using existential types in associated types --- .../impl-trait/existential-associated-type.rs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/test/ui/impl-trait/existential-associated-type.rs diff --git a/src/test/ui/impl-trait/existential-associated-type.rs b/src/test/ui/impl-trait/existential-associated-type.rs new file mode 100644 index 0000000000000..af393febfbca6 --- /dev/null +++ b/src/test/ui/impl-trait/existential-associated-type.rs @@ -0,0 +1,36 @@ +// 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)] +// compile-pass + +trait Bar {} +struct Dummy; +impl Bar for Dummy {} + +trait Foo { + type Assoc: Bar; + fn foo() -> Self::Assoc; + fn bar() -> Self::Assoc; +} + +existential type Helper: Bar; + +impl Foo for i32 { + type Assoc = Helper; + fn foo() -> Helper { + Dummy + } + fn bar() -> Helper { + Dummy + } +} + +fn main() {} From 160cbdaeeaa1e401328bdc206ff451d168ea4f1d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 16 Jul 2018 11:19:36 +0200 Subject: [PATCH 05/16] Don't call `local_def_id` twice on the same node id --- src/librustc_typeck/collect.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ab81cb8788f9c..e9510d118f7d4 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1185,8 +1185,7 @@ fn find_existential_constraints<'a, 'tcx>( found: Option<(Span, ty::Ty<'tcx>)>, } impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> { - fn check(&mut self, node_id: ast::NodeId) { - let def_id = self.tcx.hir.local_def_id(node_id); + fn check(&mut self, def_id: DefId) { // don't try to check items that cannot possibly constrain the type if !self.tcx.has_typeck_tables(def_id) { return; @@ -1221,21 +1220,24 @@ fn find_existential_constraints<'a, 'tcx>( intravisit::NestedVisitorMap::All(&self.tcx.hir) } fn visit_item(&mut self, it: &'tcx Item) { + let def_id = self.tcx.hir.local_def_id(it.id); // the existential type itself or its children are not within its reveal scope - if self.tcx.hir.local_def_id(it.id) != self.def_id { - self.check(it.id); + if def_id != self.def_id { + self.check(def_id); intravisit::walk_item(self, it); } } fn visit_impl_item(&mut self, it: &'tcx ImplItem) { + let def_id = self.tcx.hir.local_def_id(it.id); // the existential type itself or its children are not within its reveal scope - if self.tcx.hir.local_def_id(it.id) != self.def_id { - self.check(it.id); + if def_id != self.def_id { + self.check(def_id); intravisit::walk_impl_item(self, it); } } fn visit_trait_item(&mut self, it: &'tcx TraitItem) { - self.check(it.id); + let def_id = self.tcx.hir.local_def_id(it.id); + self.check(def_id); intravisit::walk_trait_item(self, it); } } From 6e09d912e5ce666ccf5af3479af1f0bbfadbd986 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 16 Jul 2018 11:20:35 +0200 Subject: [PATCH 06/16] default impls for methods can contain existential types inside --- src/librustc_typeck/collect.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e9510d118f7d4..72a4b0df6f84f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1250,6 +1250,7 @@ fn find_existential_constraints<'a, 'tcx>( match tcx.hir.get(parent) { NodeItem(ref it) => intravisit::walk_item(&mut locator, it), NodeImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it), + NodeTraitItem(ref it) => intravisit::walk_trait_item(&mut locator, it), other => bug!("{:?} is not a valid parent of an existential type item", other), } } From 35351591af5108e62127ce9f0beeca84392a06ab Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 16 Jul 2018 16:49:35 +0200 Subject: [PATCH 07/16] Move some tests around --- .../existential-associated-type.rs | 0 src/test/ui/{ => existential_types}/existential_type.nll.stderr | 0 src/test/ui/{ => existential_types}/existential_type.rs | 0 src/test/ui/{ => existential_types}/existential_type.stderr | 0 src/test/ui/{ => existential_types}/existential_type2.rs | 0 src/test/ui/{ => existential_types}/existential_type2.stderr | 0 src/test/ui/{ => existential_types}/existential_type3.rs | 0 src/test/ui/{ => existential_types}/existential_type3.stderr | 0 src/test/ui/{ => existential_types}/existential_type4.rs | 0 src/test/ui/{ => existential_types}/existential_type4.stderr | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{impl-trait => existential_types}/existential-associated-type.rs (100%) rename src/test/ui/{ => existential_types}/existential_type.nll.stderr (100%) rename src/test/ui/{ => existential_types}/existential_type.rs (100%) rename src/test/ui/{ => existential_types}/existential_type.stderr (100%) rename src/test/ui/{ => existential_types}/existential_type2.rs (100%) rename src/test/ui/{ => existential_types}/existential_type2.stderr (100%) rename src/test/ui/{ => existential_types}/existential_type3.rs (100%) rename src/test/ui/{ => existential_types}/existential_type3.stderr (100%) rename src/test/ui/{ => existential_types}/existential_type4.rs (100%) rename src/test/ui/{ => existential_types}/existential_type4.stderr (100%) diff --git a/src/test/ui/impl-trait/existential-associated-type.rs b/src/test/ui/existential_types/existential-associated-type.rs similarity index 100% rename from src/test/ui/impl-trait/existential-associated-type.rs rename to src/test/ui/existential_types/existential-associated-type.rs diff --git a/src/test/ui/existential_type.nll.stderr b/src/test/ui/existential_types/existential_type.nll.stderr similarity index 100% rename from src/test/ui/existential_type.nll.stderr rename to src/test/ui/existential_types/existential_type.nll.stderr diff --git a/src/test/ui/existential_type.rs b/src/test/ui/existential_types/existential_type.rs similarity index 100% rename from src/test/ui/existential_type.rs rename to src/test/ui/existential_types/existential_type.rs diff --git a/src/test/ui/existential_type.stderr b/src/test/ui/existential_types/existential_type.stderr similarity index 100% rename from src/test/ui/existential_type.stderr rename to src/test/ui/existential_types/existential_type.stderr diff --git a/src/test/ui/existential_type2.rs b/src/test/ui/existential_types/existential_type2.rs similarity index 100% rename from src/test/ui/existential_type2.rs rename to src/test/ui/existential_types/existential_type2.rs diff --git a/src/test/ui/existential_type2.stderr b/src/test/ui/existential_types/existential_type2.stderr similarity index 100% rename from src/test/ui/existential_type2.stderr rename to src/test/ui/existential_types/existential_type2.stderr diff --git a/src/test/ui/existential_type3.rs b/src/test/ui/existential_types/existential_type3.rs similarity index 100% rename from src/test/ui/existential_type3.rs rename to src/test/ui/existential_types/existential_type3.rs diff --git a/src/test/ui/existential_type3.stderr b/src/test/ui/existential_types/existential_type3.stderr similarity index 100% rename from src/test/ui/existential_type3.stderr rename to src/test/ui/existential_types/existential_type3.stderr diff --git a/src/test/ui/existential_type4.rs b/src/test/ui/existential_types/existential_type4.rs similarity index 100% rename from src/test/ui/existential_type4.rs rename to src/test/ui/existential_types/existential_type4.rs diff --git a/src/test/ui/existential_type4.stderr b/src/test/ui/existential_types/existential_type4.stderr similarity index 100% rename from src/test/ui/existential_type4.stderr rename to src/test/ui/existential_types/existential_type4.stderr From 0f05b4be82ae9e48b2c604b97f5436b1d43a194d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 16 Jul 2018 17:17:01 +0200 Subject: [PATCH 08/16] Split monster tests into smaller ones --- .../declared_but_never_defined.rs | 17 +++ .../declared_but_never_defined.stderr | 8 ++ .../declared_but_not_defined_in_scope.rs | 23 ++++ .../declared_but_not_defined_in_scope.stderr | 8 ++ .../different_defining_uses.rs | 25 ++++ .../different_defining_uses.stderr | 18 +++ .../different_defining_uses_never_type.rs | 29 +++++ .../different_defining_uses_never_type.stderr | 34 +++++ .../different_defining_uses_never_type2.rs | 54 ++++++++ .../existential_type.nll.stderr | 111 ---------------- .../ui/existential_types/existential_type.rs | 95 -------------- .../existential_types/existential_type.stderr | 120 ------------------ .../generic_different_defining_uses.rs | 24 ++++ .../generic_different_defining_uses.stderr | 18 +++ ...al_type4.rs => generic_nondefining_use.rs} | 0 ....stderr => generic_nondefining_use.stderr} | 4 +- ...istential_type3.rs => generic_not_used.rs} | 0 ...l_type3.stderr => generic_not_used.stderr} | 2 +- ..._type_does_not_live_long_enough.nll.stderr | 17 +++ .../generic_type_does_not_live_long_enough.rs | 21 +++ ...eric_type_does_not_live_long_enough.stderr | 18 +++ .../generic_underconstrained.rs | 22 ++++ .../generic_underconstrained.stderr | 12 ++ ..._type2.rs => generic_underconstrained2.rs} | 0 ...tderr => generic_underconstrained2.stderr} | 4 +- .../never_reveal_concrete_type.rs | 26 ++++ .../never_reveal_concrete_type.stderr | 21 +++ .../no_revealing_outside_defining_module.rs | 33 +++++ ...o_revealing_outside_defining_module.stderr | 23 ++++ 29 files changed, 456 insertions(+), 331 deletions(-) create mode 100644 src/test/ui/existential_types/declared_but_never_defined.rs create mode 100644 src/test/ui/existential_types/declared_but_never_defined.stderr create mode 100644 src/test/ui/existential_types/declared_but_not_defined_in_scope.rs create mode 100644 src/test/ui/existential_types/declared_but_not_defined_in_scope.stderr create mode 100644 src/test/ui/existential_types/different_defining_uses.rs create mode 100644 src/test/ui/existential_types/different_defining_uses.stderr create mode 100644 src/test/ui/existential_types/different_defining_uses_never_type.rs create mode 100644 src/test/ui/existential_types/different_defining_uses_never_type.stderr create mode 100644 src/test/ui/existential_types/different_defining_uses_never_type2.rs delete mode 100644 src/test/ui/existential_types/existential_type.nll.stderr delete mode 100644 src/test/ui/existential_types/existential_type.rs delete mode 100644 src/test/ui/existential_types/existential_type.stderr create mode 100644 src/test/ui/existential_types/generic_different_defining_uses.rs create mode 100644 src/test/ui/existential_types/generic_different_defining_uses.stderr rename src/test/ui/existential_types/{existential_type4.rs => generic_nondefining_use.rs} (100%) rename src/test/ui/existential_types/{existential_type4.stderr => generic_nondefining_use.stderr} (80%) rename src/test/ui/existential_types/{existential_type3.rs => generic_not_used.rs} (100%) rename src/test/ui/existential_types/{existential_type3.stderr => generic_not_used.stderr} (91%) create mode 100644 src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr create mode 100644 src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs create mode 100644 src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr create mode 100644 src/test/ui/existential_types/generic_underconstrained.rs create mode 100644 src/test/ui/existential_types/generic_underconstrained.stderr rename src/test/ui/existential_types/{existential_type2.rs => generic_underconstrained2.rs} (100%) rename src/test/ui/existential_types/{existential_type2.stderr => generic_underconstrained2.stderr} (92%) create mode 100644 src/test/ui/existential_types/never_reveal_concrete_type.rs create mode 100644 src/test/ui/existential_types/never_reveal_concrete_type.stderr create mode 100644 src/test/ui/existential_types/no_revealing_outside_defining_module.rs create mode 100644 src/test/ui/existential_types/no_revealing_outside_defining_module.stderr diff --git a/src/test/ui/existential_types/declared_but_never_defined.rs b/src/test/ui/existential_types/declared_but_never_defined.rs new file mode 100644 index 0000000000000..c0f08fe057f55 --- /dev/null +++ b/src/test/ui/existential_types/declared_but_never_defined.rs @@ -0,0 +1,17 @@ +// 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() {} + +// declared but never defined +existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses diff --git a/src/test/ui/existential_types/declared_but_never_defined.stderr b/src/test/ui/existential_types/declared_but_never_defined.stderr new file mode 100644 index 0000000000000..29ae10c1c48fb --- /dev/null +++ b/src/test/ui/existential_types/declared_but_never_defined.stderr @@ -0,0 +1,8 @@ +error: could not find defining uses + --> $DIR/declared_but_never_defined.rs:17:1 + | +LL | existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/declared_but_not_defined_in_scope.rs b/src/test/ui/existential_types/declared_but_not_defined_in_scope.rs new file mode 100644 index 0000000000000..6d0a9b80a3fc0 --- /dev/null +++ b/src/test/ui/existential_types/declared_but_not_defined_in_scope.rs @@ -0,0 +1,23 @@ +// 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() {} + +mod boo { + // declared in module but not defined inside of it + pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses +} + +fn bomp() -> boo::Boo { + "" +} diff --git a/src/test/ui/existential_types/declared_but_not_defined_in_scope.stderr b/src/test/ui/existential_types/declared_but_not_defined_in_scope.stderr new file mode 100644 index 0000000000000..fcd8e2a7f845a --- /dev/null +++ b/src/test/ui/existential_types/declared_but_not_defined_in_scope.stderr @@ -0,0 +1,8 @@ +error: could not find defining uses + --> $DIR/declared_but_not_defined_in_scope.rs:18:5 + | +LL | pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/different_defining_uses.rs b/src/test/ui/existential_types/different_defining_uses.rs new file mode 100644 index 0000000000000..c58ca3f621001 --- /dev/null +++ b/src/test/ui/existential_types/different_defining_uses.rs @@ -0,0 +1,25 @@ +// 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() {} + +// two definitions with different types +existential type Foo: std::fmt::Debug; + +fn foo() -> Foo { + "" +} + +fn bar() -> Foo { //~ ERROR defining existential type use differs from previous + 42i32 +} diff --git a/src/test/ui/existential_types/different_defining_uses.stderr b/src/test/ui/existential_types/different_defining_uses.stderr new file mode 100644 index 0000000000000..63177e8a12374 --- /dev/null +++ b/src/test/ui/existential_types/different_defining_uses.stderr @@ -0,0 +1,18 @@ +error: defining existential type use differs from previous + --> $DIR/different_defining_uses.rs:23:1 + | +LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous +LL | | 42i32 +LL | | } + | |_^ + | +note: previous use here + --> $DIR/different_defining_uses.rs:19:1 + | +LL | / fn foo() -> Foo { +LL | | "" +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/different_defining_uses_never_type.rs b/src/test/ui/existential_types/different_defining_uses_never_type.rs new file mode 100644 index 0000000000000..5bf46ef91bf7c --- /dev/null +++ b/src/test/ui/existential_types/different_defining_uses_never_type.rs @@ -0,0 +1,29 @@ +// 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() {} + +// two definitions with different types +existential type Foo: std::fmt::Debug; + +fn foo() -> Foo { + "" +} + +fn bar() -> Foo { //~ ERROR defining existential type use differs from previous + panic!() +} + +fn boo() -> Foo { //~ ERROR defining existential type use differs from previous + loop {} +} diff --git a/src/test/ui/existential_types/different_defining_uses_never_type.stderr b/src/test/ui/existential_types/different_defining_uses_never_type.stderr new file mode 100644 index 0000000000000..f0e9f505f6ec5 --- /dev/null +++ b/src/test/ui/existential_types/different_defining_uses_never_type.stderr @@ -0,0 +1,34 @@ +error: defining existential type use differs from previous + --> $DIR/different_defining_uses_never_type.rs:23:1 + | +LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous +LL | | panic!() +LL | | } + | |_^ + | +note: previous use here + --> $DIR/different_defining_uses_never_type.rs:19:1 + | +LL | / fn foo() -> Foo { +LL | | "" +LL | | } + | |_^ + +error: defining existential type use differs from previous + --> $DIR/different_defining_uses_never_type.rs:27:1 + | +LL | / fn boo() -> Foo { //~ ERROR defining existential type use differs from previous +LL | | loop {} +LL | | } + | |_^ + | +note: previous use here + --> $DIR/different_defining_uses_never_type.rs:19:1 + | +LL | / fn foo() -> Foo { +LL | | "" +LL | | } + | |_^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/existential_types/different_defining_uses_never_type2.rs b/src/test/ui/existential_types/different_defining_uses_never_type2.rs new file mode 100644 index 0000000000000..0e40221d82936 --- /dev/null +++ b/src/test/ui/existential_types/different_defining_uses_never_type2.rs @@ -0,0 +1,54 @@ +// 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() {} + +// two definitions with different types +existential type Foo: std::fmt::Debug; + +fn foo() -> Foo { + "" +} + +fn bar(arg: bool) -> Foo { + if arg { + panic!() + } else { + "bar" + } +} + +fn boo(arg: bool) -> Foo { + if arg { + loop {} + } else { + "boo" + } +} + +fn bar2(arg: bool) -> Foo { + if arg { + "bar2" + } else { + panic!() + } +} + +fn boo2(arg: bool) -> Foo { + if arg { + "boo2" + } else { + loop {} + } +} diff --git a/src/test/ui/existential_types/existential_type.nll.stderr b/src/test/ui/existential_types/existential_type.nll.stderr deleted file mode 100644 index 90840bf205ca2..0000000000000 --- a/src/test/ui/existential_types/existential_type.nll.stderr +++ /dev/null @@ -1,111 +0,0 @@ -error: defining existential type use differs from previous - --> $DIR/existential_type.rs:23:1 - | -LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous -LL | | 42i32 -LL | | } - | |_^ - | -note: previous use here - --> $DIR/existential_type.rs:19:1 - | -LL | / fn foo() -> Foo { -LL | | "" -LL | | } - | |_^ - -error[E0308]: mismatched types - --> $DIR/existential_type.rs:36:5 - | -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` - -error[E0308]: mismatched types - --> $DIR/existential_type.rs:50:23 - | -LL | let _: &str = bomp(); //~ ERROR mismatched types - | ^^^^^^ expected &str, found anonymized type - | - = note: expected type `&str` - found type `Boo` - -error[E0308]: mismatched types - --> $DIR/existential_type.rs:54:9 - | -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` - -error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/existential_type.rs:61:1 - | -LL | existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` - | - = help: consider adding a `where T: Trait` bound - = note: the return type of a function must have a statically known size - -warning: not reporting region error due to nll - --> $DIR/existential_type.rs:78:1 - | -LL | existential type WrongGeneric: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0308]: mismatched types - --> $DIR/existential_type.rs:93:27 - | -LL | let _: &'static str = x; //~ mismatched types - | ^ expected reference, found anonymized type - | - = note: expected type `&'static str` - found type `NoReveal` - -error[E0605]: non-primitive cast: `NoReveal` as `&'static str` - --> $DIR/existential_type.rs:94:13 - | -LL | let _ = x as &'static str; //~ non-primitive cast - | ^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait - -error: could not find defining uses - --> $DIR/existential_type.rs:28:1 - | -LL | existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/existential_type.rs:32:5 - | -LL | pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: defining existential type use differs from previous - --> $DIR/existential_type.rs:74:1 - | -LL | / fn my_iter2(t: T) -> MyIter { //~ ERROR defining existential type use differs from previous -LL | | Some(t).into_iter() -LL | | } - | |_^ - | -note: previous use here - --> $DIR/existential_type.rs:70:1 - | -LL | / fn my_iter(t: T) -> MyIter { -LL | | std::iter::once(t) -LL | | } - | |_^ - -error: aborting due to 10 previous errors - -Some errors occurred: E0277, E0308, E0605. -For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/existential_type.rs b/src/test/ui/existential_types/existential_type.rs deleted file mode 100644 index 6824d36204977..0000000000000 --- a/src/test/ui/existential_types/existential_type.rs +++ /dev/null @@ -1,95 +0,0 @@ -// 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() {} - -// two definitions with different types -existential type Foo: std::fmt::Debug; - -fn foo() -> Foo { - "" -} - -fn bar() -> Foo { //~ ERROR defining existential type use differs from previous - 42i32 -} - -// declared but never defined -existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses - -mod boo { - // declared in module but not defined inside of it - pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses -} - -fn bomp() -> boo::Boo { - "" //~ ERROR mismatched types -} - -mod boo2 { - mod boo { - pub existential type Boo: ::std::fmt::Debug; - fn bomp() -> Boo { - "" - } - } - - // don't actually know the type here - - fn bomp2() { - let _: &str = bomp(); //~ ERROR mismatched types - } - - fn bomp() -> boo::Boo { - "" //~ ERROR mismatched types - } -} - -// generics - -trait Trait {} -existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` - -// no `Trait` bound -fn underconstrain(_: T) -> Underconstrained { - unimplemented!() -} - -existential type MyIter: Iterator; - -fn my_iter(t: T) -> MyIter { - std::iter::once(t) -} - -fn my_iter2(t: T) -> MyIter { //~ ERROR defining existential type use differs from previous - Some(t).into_iter() -} - -existential type WrongGeneric: 'static; -//~^ ERROR the parameter type `T` may not live long enough - -fn wrong_generic(t: T) -> WrongGeneric { - t -} - -// don't reveal the concrete type -existential type NoReveal: std::fmt::Debug; - -fn define_no_reveal() -> NoReveal { - "" -} - -fn no_reveal(x: NoReveal) { - let _: &'static str = x; //~ mismatched types - let _ = x as &'static str; //~ non-primitive cast -} diff --git a/src/test/ui/existential_types/existential_type.stderr b/src/test/ui/existential_types/existential_type.stderr deleted file mode 100644 index 3e7476448bf7f..0000000000000 --- a/src/test/ui/existential_types/existential_type.stderr +++ /dev/null @@ -1,120 +0,0 @@ -error: defining existential type use differs from previous - --> $DIR/existential_type.rs:23:1 - | -LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous -LL | | 42i32 -LL | | } - | |_^ - | -note: previous use here - --> $DIR/existential_type.rs:19:1 - | -LL | / fn foo() -> Foo { -LL | | "" -LL | | } - | |_^ - -error[E0308]: mismatched types - --> $DIR/existential_type.rs:36:5 - | -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` - -error[E0308]: mismatched types - --> $DIR/existential_type.rs:50:23 - | -LL | let _: &str = bomp(); //~ ERROR mismatched types - | ^^^^^^ expected &str, found anonymized type - | - = note: expected type `&str` - found type `Boo` - -error[E0308]: mismatched types - --> $DIR/existential_type.rs:54:9 - | -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` - -error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/existential_type.rs:61:1 - | -LL | existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` - | - = help: consider adding a `where T: Trait` bound - = note: the return type of a function must have a statically known size - -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/existential_type.rs:78:1 - | -LL | existential type WrongGeneric: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | fn wrong_generic(t: T) -> WrongGeneric { - | - help: consider adding an explicit lifetime bound `T: 'static`... - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/existential_type.rs:78:1 - | -LL | existential type WrongGeneric: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0308]: mismatched types - --> $DIR/existential_type.rs:93:27 - | -LL | let _: &'static str = x; //~ mismatched types - | ^ expected reference, found anonymized type - | - = note: expected type `&'static str` - found type `NoReveal` - -error[E0605]: non-primitive cast: `NoReveal` as `&'static str` - --> $DIR/existential_type.rs:94:13 - | -LL | let _ = x as &'static str; //~ non-primitive cast - | ^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait - -error: could not find defining uses - --> $DIR/existential_type.rs:28:1 - | -LL | existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/existential_type.rs:32:5 - | -LL | pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: defining existential type use differs from previous - --> $DIR/existential_type.rs:74:1 - | -LL | / fn my_iter2(t: T) -> MyIter { //~ ERROR defining existential type use differs from previous -LL | | Some(t).into_iter() -LL | | } - | |_^ - | -note: previous use here - --> $DIR/existential_type.rs:70:1 - | -LL | / fn my_iter(t: T) -> MyIter { -LL | | std::iter::once(t) -LL | | } - | |_^ - -error: aborting due to 11 previous errors - -Some errors occurred: E0277, E0308, E0310, E0605. -For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/generic_different_defining_uses.rs b/src/test/ui/existential_types/generic_different_defining_uses.rs new file mode 100644 index 0000000000000..109f1cd913214 --- /dev/null +++ b/src/test/ui/existential_types/generic_different_defining_uses.rs @@ -0,0 +1,24 @@ +// 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 MyIter: Iterator; + +fn my_iter(t: T) -> MyIter { + std::iter::once(t) +} + +fn my_iter2(t: T) -> MyIter { //~ ERROR defining existential type use differs from previous + Some(t).into_iter() +} diff --git a/src/test/ui/existential_types/generic_different_defining_uses.stderr b/src/test/ui/existential_types/generic_different_defining_uses.stderr new file mode 100644 index 0000000000000..bc71af4c9af4b --- /dev/null +++ b/src/test/ui/existential_types/generic_different_defining_uses.stderr @@ -0,0 +1,18 @@ +error: defining existential type use differs from previous + --> $DIR/generic_different_defining_uses.rs:22:1 + | +LL | / fn my_iter2(t: T) -> MyIter { //~ ERROR defining existential type use differs from previous +LL | | Some(t).into_iter() +LL | | } + | |_^ + | +note: previous use here + --> $DIR/generic_different_defining_uses.rs:18:1 + | +LL | / fn my_iter(t: T) -> MyIter { +LL | | std::iter::once(t) +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/existential_type4.rs b/src/test/ui/existential_types/generic_nondefining_use.rs similarity index 100% rename from src/test/ui/existential_types/existential_type4.rs rename to src/test/ui/existential_types/generic_nondefining_use.rs diff --git a/src/test/ui/existential_types/existential_type4.stderr b/src/test/ui/existential_types/generic_nondefining_use.stderr similarity index 80% rename from src/test/ui/existential_types/existential_type4.stderr rename to src/test/ui/existential_types/generic_nondefining_use.stderr index b11988746eac6..3c826708649d4 100644 --- a/src/test/ui/existential_types/existential_type4.stderr +++ b/src/test/ui/existential_types/generic_nondefining_use.stderr @@ -1,5 +1,5 @@ error: non-defining existential type use in defining scope - --> $DIR/existential_type4.rs:19:1 + --> $DIR/generic_nondefining_use.rs:19:1 | LL | / fn cmp() -> Cmp { //~ ERROR non-defining existential type use in defining scope LL | | 5u32 @@ -7,7 +7,7 @@ LL | | } | |_^ | note: used non-generic type u32 for generic parameter - --> $DIR/existential_type4.rs:16:22 + --> $DIR/generic_nondefining_use.rs:16:22 | LL | existential type Cmp: 'static; | ^ diff --git a/src/test/ui/existential_types/existential_type3.rs b/src/test/ui/existential_types/generic_not_used.rs similarity index 100% rename from src/test/ui/existential_types/existential_type3.rs rename to src/test/ui/existential_types/generic_not_used.rs diff --git a/src/test/ui/existential_types/existential_type3.stderr b/src/test/ui/existential_types/generic_not_used.stderr similarity index 91% rename from src/test/ui/existential_types/existential_type3.stderr rename to src/test/ui/existential_types/generic_not_used.stderr index 90800728d7cc6..34d82c0ddb0c9 100644 --- a/src/test/ui/existential_types/existential_type3.stderr +++ b/src/test/ui/existential_types/generic_not_used.stderr @@ -1,5 +1,5 @@ error: type parameter `V` is part of concrete type but not used in parameter list for existential type - --> $DIR/existential_type3.rs:18:73 + --> $DIR/generic_not_used.rs:18:73 | LL | fn wrong_generic(_: U, v: V) -> WrongGeneric { | _________________________________________________________________________^ diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr new file mode 100644 index 0000000000000..8a6cae08ce058 --- /dev/null +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to nll + --> $DIR/generic_type_does_not_live_long_enough.rs:16:1 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/generic_type_does_not_live_long_enough.rs:20:5 + | +LL | t + | ^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs new file mode 100644 index 0000000000000..092aa1eda1646 --- /dev/null +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.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. + + +#![feature(existential_type)] + +fn main() {} + +existential type WrongGeneric: 'static; +//~^ ERROR the parameter type `T` may not live long enough + +fn wrong_generic(t: T) -> WrongGeneric { + t +} diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr new file mode 100644 index 0000000000000..cbf994defc8d9 --- /dev/null +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr @@ -0,0 +1,18 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/generic_type_does_not_live_long_enough.rs:16:1 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn wrong_generic(t: T) -> WrongGeneric { + | - help: consider adding an explicit lifetime bound `T: 'static`... + | +note: ...so that the type `T` will meet its required lifetime bounds + --> $DIR/generic_type_does_not_live_long_enough.rs:16:1 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/existential_types/generic_underconstrained.rs b/src/test/ui/existential_types/generic_underconstrained.rs new file mode 100644 index 0000000000000..fdc7a7935a2e8 --- /dev/null +++ b/src/test/ui/existential_types/generic_underconstrained.rs @@ -0,0 +1,22 @@ +// 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() {} + +trait Trait {} +existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` + +// no `Trait` bound +fn underconstrain(_: T) -> Underconstrained { + unimplemented!() +} diff --git a/src/test/ui/existential_types/generic_underconstrained.stderr b/src/test/ui/existential_types/generic_underconstrained.stderr new file mode 100644 index 0000000000000..1454ba575b1f1 --- /dev/null +++ b/src/test/ui/existential_types/generic_underconstrained.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `T: Trait` is not satisfied + --> $DIR/generic_underconstrained.rs:17:1 + | +LL | existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | + = help: consider adding a `where T: Trait` bound + = note: the return type of a function must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/existential_type2.rs b/src/test/ui/existential_types/generic_underconstrained2.rs similarity index 100% rename from src/test/ui/existential_types/existential_type2.rs rename to src/test/ui/existential_types/generic_underconstrained2.rs diff --git a/src/test/ui/existential_types/existential_type2.stderr b/src/test/ui/existential_types/generic_underconstrained2.stderr similarity index 92% rename from src/test/ui/existential_types/existential_type2.stderr rename to src/test/ui/existential_types/generic_underconstrained2.stderr index 53003a4f05d12..78e79e7fc861d 100644 --- a/src/test/ui/existential_types/existential_type2.stderr +++ b/src/test/ui/existential_types/generic_underconstrained2.stderr @@ -1,5 +1,5 @@ error[E0277]: `U` doesn't implement `std::fmt::Debug` - --> $DIR/existential_type2.rs:16:1 + --> $DIR/generic_underconstrained2.rs:16:1 | LL | existential type Underconstrained: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` @@ -9,7 +9,7 @@ LL | existential type Underconstrained: 'static; = note: the return type of a function must have a statically known size error[E0277]: `V` doesn't implement `std::fmt::Debug` - --> $DIR/existential_type2.rs:24:1 + --> $DIR/generic_underconstrained2.rs:24:1 | LL | existential type Underconstrained2: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` diff --git a/src/test/ui/existential_types/never_reveal_concrete_type.rs b/src/test/ui/existential_types/never_reveal_concrete_type.rs new file mode 100644 index 0000000000000..4517eca60ed72 --- /dev/null +++ b/src/test/ui/existential_types/never_reveal_concrete_type.rs @@ -0,0 +1,26 @@ +// 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() {} + +// don't reveal the concrete type +existential type NoReveal: std::fmt::Debug; + +fn define_no_reveal() -> NoReveal { + "" +} + +fn no_reveal(x: NoReveal) { + let _: &'static str = x; //~ mismatched types + let _ = x as &'static str; //~ non-primitive cast +} diff --git a/src/test/ui/existential_types/never_reveal_concrete_type.stderr b/src/test/ui/existential_types/never_reveal_concrete_type.stderr new file mode 100644 index 0000000000000..449799c91b79a --- /dev/null +++ b/src/test/ui/existential_types/never_reveal_concrete_type.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/never_reveal_concrete_type.rs:24:27 + | +LL | let _: &'static str = x; //~ mismatched types + | ^ expected reference, found anonymized type + | + = note: expected type `&'static str` + found type `NoReveal` + +error[E0605]: non-primitive cast: `NoReveal` as `&'static str` + --> $DIR/never_reveal_concrete_type.rs:25:13 + | +LL | let _ = x as &'static str; //~ non-primitive cast + | ^^^^^^^^^^^^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + +error: aborting due to 2 previous errors + +Some errors occurred: E0308, E0605. +For more information about an error, try `rustc --explain E0308`. 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 new file mode 100644 index 0000000000000..086df13ba7055 --- /dev/null +++ b/src/test/ui/existential_types/no_revealing_outside_defining_module.rs @@ -0,0 +1,33 @@ +// 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() {} + +mod boo2 { + mod boo { + pub existential type Boo: ::std::fmt::Debug; + fn bomp() -> Boo { + "" + } + } + + // don't actually know the type here + + fn bomp2() { + let _: &str = bomp(); //~ ERROR mismatched types + } + + fn bomp() -> boo::Boo { + "" //~ ERROR mismatched types + } +} 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 new file mode 100644 index 0000000000000..eebd329548936 --- /dev/null +++ b/src/test/ui/existential_types/no_revealing_outside_defining_module.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/no_revealing_outside_defining_module.rs:27:23 + | +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 + | +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` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 41b0315f318f208f92a2d4932b41937e06c1fdef Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 17 Jul 2018 11:20:50 +0200 Subject: [PATCH 09/16] More documentation --- src/librustc/infer/anon_types/mod.rs | 17 +++++++++++++++++ src/librustc/ty/mod.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index 5e731871e2851..8cc8abda70800 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -808,6 +808,23 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { } /// Whether `anon_node_id` is a sibling or a child of a sibling of `def_id` +/// +/// ```rust +/// pub mod foo { +/// pub mod bar { +/// pub existential type Baz; +/// +/// fn f1() -> Baz { .. } +/// } +/// +/// fn f2() -> bar::Baz { .. } +/// } +/// ``` +/// +/// Here, `def_id` will be the `DefId` of the existential type `Baz`. +/// `anon_node_id` is the `NodeId` of the reference to Baz -- so either the return type of f1 or f2. +/// We will return true if the reference is within the same module as the existential type +/// So true for f1, false for f2. pub fn may_define_existential_type( tcx: TyCtxt, def_id: DefId, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2e221424e3ce0..7ae6f81264981 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2861,7 +2861,7 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> { - // The param_env of an existential type is its parent's param_env + // The param_env of an impl Trait type is its defining function's param_env if let Some(Def::Existential(_)) = tcx.describe_def(def_id) { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { if let hir::map::NodeItem(item) = tcx.hir.get(node_id) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d2c9622199160..cd6a1e3fdba22 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -535,6 +535,26 @@ fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, check_where_clauses(tcx, fcx, span, def_id, Some(sig.output())); } +/// Checks "defining uses" of existential types to ensure that they meet the restrictions laid for +/// "higher-order pattern unification". +/// This ensures that inference is tractable. +/// In particular, definitions of existential types can only use other generics as arguments, +/// and they cannot repeat an argument. Example: +/// +/// ```rust +/// existential type Foo; +/// +/// // ok -- `Foo` is applied to two distinct, generic types. +/// fn a() -> Foo { .. } +/// +/// // not ok -- `Foo` is applied to `T` twice. +/// fn b() -> Foo { .. } +/// +/// +/// // not ok -- `Foo` is applied to a non-generic type. +/// fn b() -> Foo { .. } +/// ``` +/// fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'gcx>, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, From 8c1b0d772ee293e65e526e1309f4070fbcb4105a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 17 Jul 2018 11:21:10 +0200 Subject: [PATCH 10/16] Simplify defining scope logic --- src/librustc/infer/anon_types/mod.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index 8cc8abda70800..2cb47c7beb53a 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -690,38 +690,35 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { // } // ``` if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) { - let anon_parent_def_id = match tcx.hir.expect_item(anon_node_id).node { + let in_definition_scope = match tcx.hir.expect_item(anon_node_id).node { // impl trait hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(parent), .. - }) => parent, + }) => parent == self.parent_def_id, // named existential types hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: None, .. - }) if may_define_existential_type( + }) => may_define_existential_type( tcx, self.parent_def_id, anon_node_id, - ) => { - return self.fold_anon_ty(ty, def_id, substs); - }, + ), _ => { let anon_parent_node_id = tcx.hir.get_parent(anon_node_id); - tcx.hir.local_def_id(anon_parent_node_id) + self.parent_def_id == tcx.hir.local_def_id(anon_parent_node_id) }, }; - if self.parent_def_id == anon_parent_def_id { + if in_definition_scope { return self.fold_anon_ty(ty, def_id, substs); } debug!( "instantiate_anon_types_in_map: \ - encountered anon with wrong parent \ - def_id={:?} \ - anon_parent_def_id={:?}", - def_id, anon_parent_def_id + encountered anon outside it's definition scope \ + def_id={:?}", + def_id, ); } } From 240fcdf65b183e64a7dc4f5992c72194226636b7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 17 Jul 2018 11:21:26 +0200 Subject: [PATCH 11/16] Match ergonomics --- src/librustc_save_analysis/dump_visitor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 58189ee0a2f10..ac7085a55cfe0 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1243,7 +1243,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { // 'def' and the name here should be a ref to the def in the // trait. for bound in bounds.iter() { - if let ast::GenericBound::Trait(ref trait_ref, _) = *bound { + if let ast::GenericBound::Trait(trait_ref, _) = bound { self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path) } } From feb139f53f62b936ad94e9449212e130a71723b7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 17 Jul 2018 11:21:54 +0200 Subject: [PATCH 12/16] Check lifetimes on existential types --- src/librustc/infer/anon_types/mod.rs | 1 + src/librustc/ty/fold.rs | 14 +++- src/librustc_typeck/check/wfcheck.rs | 48 ++++++++++++-- src/librustc_typeck/check/writeback.rs | 64 ++++++++++++++++--- .../generic_duplicate_lifetime_param.rs | 20 ++++++ .../generic_duplicate_lifetime_param.stderr | 16 +++++ .../generic_duplicate_param_use.rs | 20 ++++++ .../generic_duplicate_param_use.stderr | 9 +++ .../generic_lifetime_param.rs | 21 ++++++ .../no_revealing_outside_defining_module.rs | 28 ++++---- ...o_revealing_outside_defining_module.stderr | 16 ++--- 11 files changed, 218 insertions(+), 39 deletions(-) create mode 100644 src/test/ui/existential_types/generic_duplicate_lifetime_param.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_lifetime_param.stderr create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use.stderr create mode 100644 src/test/ui/existential_types/generic_lifetime_param.rs 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` From fdd719aa3df9bdbbd64b26ca12955605e57ea566 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 17 Jul 2018 13:44:42 +0200 Subject: [PATCH 13/16] Prepare for using wfcheck on existential types --- src/librustc/ty/mod.rs | 24 +++++++++++-------- src/librustc/ty/wf.rs | 8 ++++++- src/librustc_typeck/astconv.rs | 12 +++------- ..._type_does_not_live_long_enough.nll.stderr | 21 ++++++++-------- .../generic_type_does_not_live_long_enough.rs | 7 ++++-- ...eric_type_does_not_live_long_enough.stderr | 18 ++++++++++---- 6 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7ae6f81264981..178f0d3cdcbc1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2856,22 +2856,26 @@ fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option }) } +/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition +pub fn is_impl_trait_defn(tcx: TyCtxt, def_id: DefId) -> Option { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + if let hir::map::NodeItem(item) = tcx.hir.get(node_id) { + if let hir::ItemKind::Existential(ref exist_ty) = item.node { + return exist_ty.impl_trait_fn; + } + } + } + None +} + /// See `ParamEnv` struct def'n for details. fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> { // The param_env of an impl Trait type is its defining function's param_env - if let Some(Def::Existential(_)) = tcx.describe_def(def_id) { - if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { - if let hir::map::NodeItem(item) = tcx.hir.get(node_id) { - if let hir::ItemKind::Existential(ref exist_ty) = item.node { - if let Some(parent) = exist_ty.impl_trait_fn { - return param_env(tcx, parent); - } - } - } - } + if let Some(parent) = is_impl_trait_defn(tcx, def_id) { + return param_env(tcx, parent); } // Compute the bounds on Self and the type parameters. diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 5376acca0d8cd..b99cdd59773aa 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -360,10 +360,16 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // types appearing in the fn signature } - ty::TyAnon(..) => { + ty::TyAnon(did, substs) => { // all of the requirements on type parameters // should've been checked by the instantiation // of whatever returned this exact `impl Trait`. + + // for named existential types we still need to check them + if super::is_impl_trait_defn(self.infcx.tcx, did).is_none() { + let obligations = self.nominal_obligations(did, substs); + self.out.extend(obligations); + } } ty::TyDynamic(data, r) => { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 60aea074f2421..465faa1d4779c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1037,15 +1037,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { match path.def { Def::Existential(did) => { // check for desugared impl trait - if let Some(node_id) = tcx.hir.as_local_node_id(did) { - if let hir::map::NodeItem(item) = tcx.hir.get(node_id) { - if let hir::ItemKind::Existential(ref exist_ty) = item.node { - if exist_ty.impl_trait_fn.is_some() { - let lifetimes = &path.segments[0].args.as_ref().unwrap().args; - return self.impl_trait_ty_to_ty(did, lifetimes); - } - } - } + if ty::is_impl_trait_defn(tcx, did).is_some() { + let lifetimes = &path.segments[0].args.as_ref().unwrap().args; + return self.impl_trait_ty_to_ty(did, lifetimes); } let item_segment = path.segments.split_last().unwrap(); self.prohibit_generics(item_segment.1); diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr index 8a6cae08ce058..84af8e1dca2b1 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr @@ -1,17 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/generic_type_does_not_live_long_enough.rs:16:18 + | +LL | let z: i32 = x; //~ ERROR mismatched types + | ^ expected i32, found anonymized type + | + = note: expected type `i32` + found type `WrongGeneric::<&{integer}>` + warning: not reporting region error due to nll - --> $DIR/generic_type_does_not_live_long_enough.rs:16:1 + --> $DIR/generic_type_does_not_live_long_enough.rs:19:1 | LL | existential type WrongGeneric: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/generic_type_does_not_live_long_enough.rs:20:5 - | -LL | t - | ^ - | - = help: consider adding an explicit lifetime bound `T: 'static`... - error: aborting due to previous error -For more information about this error, try `rustc --explain E0310`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs index 092aa1eda1646..440fc2d128404 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs @@ -8,10 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - #![feature(existential_type)] -fn main() {} +fn main() { + let y = 42; + let x = wrong_generic(&y); + let z: i32 = x; //~ ERROR mismatched types +} existential type WrongGeneric: 'static; //~^ ERROR the parameter type `T` may not live long enough diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr index cbf994defc8d9..189ad7d49a485 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr @@ -1,5 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/generic_type_does_not_live_long_enough.rs:16:18 + | +LL | let z: i32 = x; //~ ERROR mismatched types + | ^ expected i32, found anonymized type + | + = note: expected type `i32` + found type `WrongGeneric::<&{integer}>` + error[E0310]: the parameter type `T` may not live long enough - --> $DIR/generic_type_does_not_live_long_enough.rs:16:1 + --> $DIR/generic_type_does_not_live_long_enough.rs:19:1 | LL | existential type WrongGeneric: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,11 +17,12 @@ LL | fn wrong_generic(t: T) -> WrongGeneric { | - help: consider adding an explicit lifetime bound `T: 'static`... | note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/generic_type_does_not_live_long_enough.rs:16:1 + --> $DIR/generic_type_does_not_live_long_enough.rs:19:1 | LL | existential type WrongGeneric: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0310`. +Some errors occurred: E0308, E0310. +For more information about an error, try `rustc --explain E0308`. From f3b44929856283c43742f86692349c27bb701034 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 17 Jul 2018 15:11:00 +0200 Subject: [PATCH 14/16] Add some tests around associated types --- .../ui/existential_types/bound_reduction.rs | 30 +++++++++++++++++++ .../ui/existential_types/bound_reduction2.rs | 28 +++++++++++++++++ .../existential_types/bound_reduction2.stderr | 16 ++++++++++ .../no_revealing_outside_defining_module.rs | 2 +- .../ui/existential_types/not_well_formed.rs | 28 +++++++++++++++++ .../existential_types/not_well_formed.stderr | 9 ++++++ 6 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/existential_types/bound_reduction.rs create mode 100644 src/test/ui/existential_types/bound_reduction2.rs create mode 100644 src/test/ui/existential_types/bound_reduction2.stderr create mode 100644 src/test/ui/existential_types/not_well_formed.rs create mode 100644 src/test/ui/existential_types/not_well_formed.stderr diff --git a/src/test/ui/existential_types/bound_reduction.rs b/src/test/ui/existential_types/bound_reduction.rs new file mode 100644 index 0000000000000..2e42c92ab30a3 --- /dev/null +++ b/src/test/ui/existential_types/bound_reduction.rs @@ -0,0 +1,30 @@ +// 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 + +#![allow(warnings)] + +#![feature(existential_type)] + +fn main() { +} + +existential type Foo: std::fmt::Debug; + +trait Trait {} + +fn foo_desugared>(_: T) -> Foo { + (42, std::marker::PhantomData::) +} diff --git a/src/test/ui/existential_types/bound_reduction2.rs b/src/test/ui/existential_types/bound_reduction2.rs new file mode 100644 index 0000000000000..d098a4ef4c8e7 --- /dev/null +++ b/src/test/ui/existential_types/bound_reduction2.rs @@ -0,0 +1,28 @@ +// 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() { +} + +trait TraitWithAssoc { + type Assoc; +} + +existential type Foo: Trait; + +trait Trait {} + +impl Trait for () {} + +fn foo_desugared(_: T) -> Foo { //~ ERROR non-defining + () +} diff --git a/src/test/ui/existential_types/bound_reduction2.stderr b/src/test/ui/existential_types/bound_reduction2.stderr new file mode 100644 index 0000000000000..33b8b71bffb13 --- /dev/null +++ b/src/test/ui/existential_types/bound_reduction2.stderr @@ -0,0 +1,16 @@ +error: non-defining existential type use in defining scope + --> $DIR/bound_reduction2.rs:26:1 + | +LL | / fn foo_desugared(_: T) -> Foo { //~ ERROR non-defining +LL | | () +LL | | } + | |_^ + | +note: used non-generic type ::Assoc for generic parameter + --> $DIR/bound_reduction2.rs:20:22 + | +LL | existential type Foo: Trait; + | ^ + +error: aborting due to previous error + 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 41c17c357bc80..f646891b3b4fa 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 @@ -32,4 +32,4 @@ fn bomp() -> boo::Boo { fn bomp_loop() -> boo::Boo { loop {} -} \ No newline at end of file +} diff --git a/src/test/ui/existential_types/not_well_formed.rs b/src/test/ui/existential_types/not_well_formed.rs new file mode 100644 index 0000000000000..b3d38aee8c533 --- /dev/null +++ b/src/test/ui/existential_types/not_well_formed.rs @@ -0,0 +1,28 @@ +// 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() { +} + +trait TraitWithAssoc { + type Assoc; +} + +existential type Foo: Trait; //~ associated type `Assoc` not found for `V` + +trait Trait {} + +impl Trait for () {} + +fn foo_desugared(_: T) -> Foo { + () +} diff --git a/src/test/ui/existential_types/not_well_formed.stderr b/src/test/ui/existential_types/not_well_formed.stderr new file mode 100644 index 0000000000000..6b7d1be98a772 --- /dev/null +++ b/src/test/ui/existential_types/not_well_formed.stderr @@ -0,0 +1,9 @@ +error[E0220]: associated type `Assoc` not found for `V` + --> $DIR/not_well_formed.rs:20:32 + | +LL | existential type Foo: Trait; //~ associated type `Assoc` not found for `V` + | ^^^^^^^^ associated type `Assoc` not found + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0220`. From 442d5d83e29470ef07d29bd02f7974c7d99fae91 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 18 Jul 2018 13:54:32 +0200 Subject: [PATCH 15/16] Adjust run pass test to stricter existential type rules --- src/test/run-pass/existential_type.rs | 25 ++-------------- .../existential_types/unused_generic_param.rs | 30 +++++++++++++++++++ .../unused_generic_param.stderr | 15 ++++++++++ 3 files changed, 48 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/existential_types/unused_generic_param.rs create mode 100644 src/test/ui/existential_types/unused_generic_param.stderr diff --git a/src/test/run-pass/existential_type.rs b/src/test/run-pass/existential_type.rs index d2cecd83036ec..e63d5c2293a81 100644 --- a/src/test/run-pass/existential_type.rs +++ b/src/test/run-pass/existential_type.rs @@ -75,10 +75,10 @@ fn my_other_iter(u: U) -> MyOtherIter { } trait Trait {} -existential type GenericBound: 'static; +existential type GenericBound<'a, T: Trait>: 'a; -fn generic_bound(_: T) -> GenericBound { - unimplemented!() +fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> { + t } mod pass_through { @@ -92,22 +92,3 @@ mod pass_through { fn use_passthrough(x: pass_through::Passthrough) -> pass_through::Passthrough { x } - -existential type PartiallyDefined: 'static; - -// doesn't declare all PartiallyDefined for all possible `T`, but since it's the only -// function producing the value, noone can ever get a value that is problematic -fn partially_defined(_: T) -> PartiallyDefined { - 4u32 -} - -existential type PartiallyDefined2: 'static; - -fn partially_defined2(_: T) -> PartiallyDefined2 { - 4u32 -} - -// fully defines PartiallyDefine2 -fn partially_defined22(_: T) -> PartiallyDefined2 { - 4u32 -} diff --git a/src/test/ui/existential_types/unused_generic_param.rs b/src/test/ui/existential_types/unused_generic_param.rs new file mode 100644 index 0000000000000..420ce89cc37c1 --- /dev/null +++ b/src/test/ui/existential_types/unused_generic_param.rs @@ -0,0 +1,30 @@ +// 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 PartiallyDefined: 'static; //~ `T` is unused + +fn partially_defined(_: T) -> PartiallyDefined { + 4u32 +} + +existential type PartiallyDefined2: 'static; //~ `T` is unused + +fn partially_defined2(_: T) -> PartiallyDefined2 { + 4u32 +} + +fn partially_defined22(_: T) -> PartiallyDefined2 { + 4u32 +} diff --git a/src/test/ui/existential_types/unused_generic_param.stderr b/src/test/ui/existential_types/unused_generic_param.stderr new file mode 100644 index 0000000000000..7ad5eab0b0a67 --- /dev/null +++ b/src/test/ui/existential_types/unused_generic_param.stderr @@ -0,0 +1,15 @@ +error[E0091]: type parameter `T` is unused + --> $DIR/unused_generic_param.rs:16:35 + | +LL | existential type PartiallyDefined: 'static; //~ `T` is unused + | ^ unused type parameter + +error[E0091]: type parameter `T` is unused + --> $DIR/unused_generic_param.rs:22:36 + | +LL | existential type PartiallyDefined2: 'static; //~ `T` is unused + | ^ unused type parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0091`. From 9017f79282f1d745453a5117af25a3b477600a90 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 19 Jul 2018 10:23:56 +0200 Subject: [PATCH 16/16] Generate a page for existential types --- src/librustdoc/html/render.rs | 41 +++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 928d7d38351f8..ceb43a3729bd8 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2103,6 +2103,7 @@ impl<'a> fmt::Display for Item<'a> { clean::ConstantItem(..) => write!(fmt, "Constant ")?, clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?, clean::KeywordItem(..) => write!(fmt, "Keyword ")?, + clean::ExistentialItem(..) => write!(fmt, "Existential Type ")?, _ => { // We don't generate pages for any other type. unreachable!(); @@ -2167,6 +2168,7 @@ impl<'a> fmt::Display for Item<'a> { clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c), clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item), clean::KeywordItem(ref k) => item_keyword(fmt, self.cx, self.item, k), + clean::ExistentialItem(ref e, _) => item_existential(fmt, self.cx, self.item, e), _ => { // We don't generate pages for any other type. unreachable!(); @@ -2685,18 +2687,17 @@ fn render_impls(cx: &Context, w: &mut fmt::Formatter, Ok(()) } -fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, - t: &clean::Trait) -> fmt::Result { +fn bounds(t_bounds: &[clean::GenericBound]) -> String { let mut bounds = String::new(); let mut bounds_plain = String::new(); - if !t.bounds.is_empty() { + if !t_bounds.is_empty() { if !bounds.is_empty() { bounds.push(' '); bounds_plain.push(' '); } bounds.push_str(": "); bounds_plain.push_str(": "); - for (i, p) in t.bounds.iter().enumerate() { + for (i, p) in t_bounds.iter().enumerate() { if i > 0 { bounds.push_str(" + "); bounds_plain.push_str(" + "); @@ -2705,7 +2706,16 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, bounds_plain.push_str(&format!("{:#}", *p)); } } + bounds +} +fn item_trait( + w: &mut fmt::Formatter, + cx: &Context, + it: &clean::Item, + t: &clean::Trait, +) -> fmt::Result { + let bounds = bounds(&t.bounds); let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); let required = t.items.iter().filter(|m| m.is_ty_method()).collect::>(); @@ -3905,6 +3915,29 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi Ok(()) } +fn item_existential( + w: &mut fmt::Formatter, + cx: &Context, + it: &clean::Item, + t: &clean::Existential, +) -> fmt::Result { + write!(w, "
")?;
+    render_attributes(w, it)?;
+    write!(w, "existential type {}{}{where_clause}: {bounds};
", + it.name.as_ref().unwrap(), + t.generics, + where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true }, + bounds = bounds(&t.bounds))?; + + document(w, cx, it)?; + + // Render any items associated directly to this alias, as otherwise they + // won't be visible anywhere in the docs. It would be nice to also show + // associated items from the aliased type (see discussion in #32077), but + // we need #14072 to make sense of the generics. + render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) +} + fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Typedef) -> fmt::Result { write!(w, "
")?;