From 5558fe8a9207b000b1cab9f3d521b06b144d6f8f Mon Sep 17 00:00:00 2001 From: Ohad Ravid Date: Fri, 1 Nov 2019 13:50:36 +0100 Subject: [PATCH 1/2] Suggest correct code when encountering an incorrect trait bound referencing the current trait --- src/librustc_typeck/astconv.rs | 18 +++++++++++++++++- src/librustc_typeck/check/mod.rs | 4 ++++ src/librustc_typeck/collect.rs | 4 ++++ .../associated-types-in-ambiguous-context.rs | 7 +++++++ ...ssociated-types-in-ambiguous-context.stderr | 10 ++++++++-- 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index aa05a08686a99..8bcf51eb9e3c0 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -43,6 +43,8 @@ pub struct PathSeg(pub DefId, pub usize); pub trait AstConv<'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; + fn item_def_id(&self) -> Option; + /// Returns predicates in scope of the form `X: Foo`, where `X` is /// a type parameter `X` with the given id `def_id`. This is a /// subset of the full set of predicates. @@ -1759,17 +1761,31 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { -> Ty<'tcx> { let tcx = self.tcx(); + let trait_def_id = tcx.parent(item_def_id).unwrap(); + debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id); + self.prohibit_generics(slice::from_ref(item_segment)); let self_ty = if let Some(ty) = opt_self_ty { ty } else { let path_str = tcx.def_path_str(trait_def_id); + + // If the trait in segment is the same as the trait defining the item, + // use the `` syntax in the error. + debug!("qpath_to_ty: self.item_def_id()={:?}", self.item_def_id()); + + let type_name = if self.item_def_id() == Some(trait_def_id) { + "Self" + } else { + "Type" + }; + self.report_ambiguous_associated_type( span, - "Type", + type_name, &path_str, item_segment.ident.name, ); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f7132cd868aac..a2af29aef094b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2279,6 +2279,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.tcx } + fn item_def_id(&self) -> Option { + None + } + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 001d98aece2a0..7ef842cb7579c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -182,6 +182,10 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx } + fn item_def_id(&self) -> Option { + Some(self.item_def_id) + } + fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { self.tcx .at(span) diff --git a/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs b/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs index 1b1ea9d52a98d..202eecfa7b7f5 100644 --- a/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs +++ b/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs @@ -12,6 +12,13 @@ trait Grab { //~^ ERROR ambiguous associated type } +trait Bar {} + +trait Foo where Foo::Assoc: Bar { +//~^ ERROR ambiguous associated type + type Assoc; +} + type X = std::ops::Deref::Target; //~^ ERROR ambiguous associated type diff --git a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr index 83667b54807e2..db6dec6e899dc 100644 --- a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -5,7 +5,13 @@ LL | fn get(x: T, y: U) -> Get::Value {} | ^^^^^^^^^^ help: use fully-qualified syntax: `::Value` error[E0223]: ambiguous associated type - --> $DIR/associated-types-in-ambiguous-context.rs:15:10 + --> $DIR/associated-types-in-ambiguous-context.rs:17:17 + | +LL | trait Foo where Foo::Assoc: Bar { + | ^^^^^^^^^^ help: use fully-qualified syntax: `::Assoc` + +error[E0223]: ambiguous associated type + --> $DIR/associated-types-in-ambiguous-context.rs:22:10 | LL | type X = std::ops::Deref::Target; | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::Target` @@ -16,6 +22,6 @@ error[E0223]: ambiguous associated type LL | fn grab(&self) -> Grab::Value; | ^^^^^^^^^^^ help: use fully-qualified syntax: `::Value` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0223`. From 8c909344ed19c9f9a51f82c8e270ded09671fd8b Mon Sep 17 00:00:00 2001 From: Ohad Ravid Date: Sat, 2 Nov 2019 09:49:05 +0100 Subject: [PATCH 2/2] Suggest more likely code when encountering an incorrect assoc item referencing the current trait --- src/librustc_typeck/astconv.rs | 14 ++++++++++++-- .../associated-types-in-ambiguous-context.rs | 3 +++ .../associated-types-in-ambiguous-context.stderr | 14 ++++++++++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 8bcf51eb9e3c0..b14121da79f59 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1773,11 +1773,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { let path_str = tcx.def_path_str(trait_def_id); + let def_id = self.item_def_id(); + + debug!("qpath_to_ty: self.item_def_id()={:?}", def_id); + + let parent_def_id = def_id.and_then(|def_id| tcx.hir().as_local_hir_id(def_id)) + .map(|hir_id| tcx.hir().get_parent_did(hir_id)); + + debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id); + // If the trait in segment is the same as the trait defining the item, // use the `` syntax in the error. - debug!("qpath_to_ty: self.item_def_id()={:?}", self.item_def_id()); + let is_part_of_self_trait_constraints = def_id == Some(trait_def_id); + let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id); - let type_name = if self.item_def_id() == Some(trait_def_id) { + let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { "Self" } else { "Type" diff --git a/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs b/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs index 202eecfa7b7f5..51b53908f98c3 100644 --- a/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs +++ b/src/test/ui/associated-types/associated-types-in-ambiguous-context.rs @@ -10,6 +10,9 @@ trait Grab { type Value; fn grab(&self) -> Grab::Value; //~^ ERROR ambiguous associated type + + fn get(&self) -> Get::Value; + //~^ ERROR ambiguous associated type } trait Bar {} diff --git a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr index db6dec6e899dc..77835c5f6766e 100644 --- a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -5,13 +5,13 @@ LL | fn get(x: T, y: U) -> Get::Value {} | ^^^^^^^^^^ help: use fully-qualified syntax: `::Value` error[E0223]: ambiguous associated type - --> $DIR/associated-types-in-ambiguous-context.rs:17:17 + --> $DIR/associated-types-in-ambiguous-context.rs:20:17 | LL | trait Foo where Foo::Assoc: Bar { | ^^^^^^^^^^ help: use fully-qualified syntax: `::Assoc` error[E0223]: ambiguous associated type - --> $DIR/associated-types-in-ambiguous-context.rs:22:10 + --> $DIR/associated-types-in-ambiguous-context.rs:25:10 | LL | type X = std::ops::Deref::Target; | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::Target` @@ -20,8 +20,14 @@ error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:11:23 | LL | fn grab(&self) -> Grab::Value; - | ^^^^^^^^^^^ help: use fully-qualified syntax: `::Value` + | ^^^^^^^^^^^ help: use fully-qualified syntax: `::Value` -error: aborting due to 4 previous errors +error[E0223]: ambiguous associated type + --> $DIR/associated-types-in-ambiguous-context.rs:14:22 + | +LL | fn get(&self) -> Get::Value; + | ^^^^^^^^^^ help: use fully-qualified syntax: `::Value` + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0223`.