From 3980342f3164a62ba7036711c16cc8af20d06418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 3 Dec 2019 22:19:18 -0800 Subject: [PATCH 01/18] Use structured suggestion for disambiguating method calls Fix #65635. --- src/librustc/ty/mod.rs | 11 ++ src/librustc_typeck/check/expr.rs | 3 +- src/librustc_typeck/check/method/suggest.rs | 127 +++++++++++++----- .../associated-const-ambiguity-report.stderr | 10 +- src/test/ui/error-codes/E0034.stderr | 10 +- .../inference_unstable_featured.stderr | 10 +- src/test/ui/issues/issue-18446.stderr | 6 +- src/test/ui/issues/issue-3702-2.stderr | 10 +- .../issue-65634-raw-ident-suggestion.stderr | 10 +- ...method-ambig-two-traits-cross-crate.stderr | 10 +- ...method-ambig-two-traits-from-bounds.stderr | 10 +- .../method-ambig-two-traits-from-impls.stderr | 10 +- ...method-ambig-two-traits-from-impls2.stderr | 10 +- ...mbig-two-traits-with-default-method.stderr | 10 +- ...e-trait-object-with-separate-params.stderr | 15 ++- src/test/ui/span/issue-37767.stderr | 30 ++++- src/test/ui/span/issue-7575.stderr | 20 ++- .../ui/traits/trait-alias-ambiguous.stderr | 10 +- 18 files changed, 248 insertions(+), 74 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 78a31f4e54466..15bbfa7860fa7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -212,6 +212,17 @@ pub enum AssocKind { Type } +impl AssocKind { + pub fn suggestion_descr(&self) -> &'static str { + match self { + ty::AssocKind::Method => "method call", + ty::AssocKind::Type | + ty::AssocKind::OpaqueTy => "associated type", + ty::AssocKind::Const => "associated constant", + } + } +} + impl AssocItem { pub fn def_kind(&self) -> DefKind { match self.kind { diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 5bfc60c754067..b11a8a7ab5336 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1422,8 +1422,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field: ast::Ident, ) -> Ty<'tcx> { let expr_t = self.check_expr_with_needs(base, needs); - let expr_t = self.structurally_resolved_type(base.span, - expr_t); + let expr_t = self.structurally_resolved_type(base.span, expr_t); let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, _)) = autoderef.next() { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f4b53b4d10604..cd26e6f237c7d 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -82,34 +82,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let print_disambiguation_help = | err: &mut DiagnosticBuilder<'_>, trait_name: String, + rcvr_ty: Ty<'_>, + kind: ty::AssocKind, + span: Span, + candidate: Option, | { - err.help(&format!( - "to disambiguate the method call, write `{}::{}({}{})` instead", - trait_name, - item_name, - if rcvr_ty.is_region_ptr() && args.is_some() { - if rcvr_ty.is_mutable_ptr() { - "&mut " + let mut applicability = Applicability::MachineApplicable; + let sugg_args = if let ty::AssocKind::Method = kind { + format!( + "({}{})", + if rcvr_ty.is_region_ptr() && args.is_some() { + if rcvr_ty.is_mutable_ptr() { + "&mut " + } else { + "&" + } } else { - "&" - } - } else { - "" - }, - args.map(|arg| arg - .iter() - .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span) - .unwrap_or_else(|_| "...".to_owned())) - .collect::>() - .join(", ") - ).unwrap_or_else(|| "...".to_owned()) - )); + "" + }, + args.map(|arg| arg + .iter() + .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span) + .unwrap_or_else(|_| { + applicability = Applicability::HasPlaceholders; + "...".to_owned() + })) + .collect::>() + .join(", ") + ).unwrap_or_else(|| { + applicability = Applicability::HasPlaceholders; + "...".to_owned() + }), + ) + } else { + String::new() + }; + let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args); + err.span_suggestion( + span, + &format!( + "disambiguate the {} for {}", + kind.suggestion_descr(), + if let Some(candidate) = candidate { + format!("candidate #{}", candidate) + } else { + "the candidate".to_string() + }, + ), + sugg, + applicability, + ); }; let report_candidates = | span: Span, err: &mut DiagnosticBuilder<'_>, mut sources: Vec, + sugg_span: Span, | { sources.sort(); sources.dedup(); @@ -150,15 +179,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let note_str = if sources.len() > 1 { - format!("candidate #{} is defined in an impl{} for the type `{}`", - idx + 1, - insertion, - impl_ty) + let (note_str, idx) = if sources.len() > 1 { + (format!( + "candidate #{} is defined in an impl{} for the type `{}`", + idx + 1, + insertion, + impl_ty, + ), Some(idx + 1)) } else { - format!("the candidate is defined in an impl{} for the type `{}`", - insertion, - impl_ty) + (format!( + "the candidate is defined in an impl{} for the type `{}`", + insertion, + impl_ty, + ), None) }; if let Some(note_span) = note_span { // We have a span pointing to the method. Show note with snippet. @@ -168,7 +201,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(¬e_str); } if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) { - print_disambiguation_help(err, self.tcx.def_path_str(trait_ref.def_id)); + let path = self.tcx.def_path_str(trait_ref.def_id); + + let ty = match item.kind { + ty::AssocKind::Const | + ty::AssocKind::Type | + ty::AssocKind::OpaqueTy => rcvr_ty, + ty::AssocKind::Method => self.tcx.fn_sig(item.def_id) + .inputs() + .skip_binder() + .get(0) + .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr()) + .map(|ty| *ty) + .unwrap_or(rcvr_ty), + }; + print_disambiguation_help(err, path, ty, item.kind, sugg_span, idx); } } CandidateSource::TraitSource(trait_did) => { @@ -182,19 +229,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let item_span = self.tcx.sess.source_map() .def_span(self.tcx.def_span(item.def_id)); - if sources.len() > 1 { + let idx = if sources.len() > 1 { span_note!(err, item_span, "candidate #{} is defined in the trait `{}`", idx + 1, self.tcx.def_path_str(trait_did)); + Some(idx + 1) } else { span_note!(err, item_span, "the candidate is defined in the trait `{}`", self.tcx.def_path_str(trait_did)); - } - print_disambiguation_help(err, self.tcx.def_path_str(trait_did)); + None + }; + let path = self.tcx.def_path_str(trait_did); + print_disambiguation_help(err, path, rcvr_ty, item.kind, sugg_span, idx); } } } @@ -203,6 +253,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; + let sugg_span = if let SelfSource::MethodCall(expr) = source { + // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing. + self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span + } else { + span + }; + match error { MethodError::NoMatch(NoMatchData { static_candidates: static_sources, @@ -495,9 +552,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - report_candidates(span, &mut err, static_sources); + report_candidates(span, &mut err, static_sources, sugg_span); } else if static_sources.len() > 1 { - report_candidates(span, &mut err, static_sources); + report_candidates(span, &mut err, static_sources, sugg_span); } if !unsatisfied_predicates.is_empty() { @@ -584,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "multiple applicable items in scope"); err.span_label(span, format!("multiple `{}` found", item_name)); - report_candidates(span, &mut err, sources); + report_candidates(span, &mut err, sources, sugg_span); err.emit(); } diff --git a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr index bb217bd182db6..92a8d19021a2c 100644 --- a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr +++ b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `i32` | LL | const ID: i32 = 1; | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Foo::ID(...)` instead note: candidate #2 is defined in an impl of the trait `Bar` for the type `i32` --> $DIR/associated-const-ambiguity-report.rs:14:5 | LL | const ID: i32 = 3; | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Bar::ID(...)` instead +help: disambiguate the associated constant for candidate #1 + | +LL | const X: i32 = Foo::ID; + | ^^^^^^^ +help: disambiguate the associated constant for candidate #2 + | +LL | const X: i32 = Bar::ID; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr index a58d16bfafb59..30b44fd402bb8 100644 --- a/src/test/ui/error-codes/E0034.stderr +++ b/src/test/ui/error-codes/E0034.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Trait1` for the type `Tes | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `Trait1::foo(...)` instead note: candidate #2 is defined in an impl of the trait `Trait2` for the type `Test` --> $DIR/E0034.rs:16:5 | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `Trait2::foo(...)` instead +help: disambiguate the method call for candidate #1 + | +LL | Trait1::foo(...)() + | ^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | Trait2::foo(...)() + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/inference/inference_unstable_featured.stderr b/src/test/ui/inference/inference_unstable_featured.stderr index b06a6298a571c..fa908440e41ea 100644 --- a/src/test/ui/inference/inference_unstable_featured.stderr +++ b/src/test/ui/inference/inference_unstable_featured.stderr @@ -5,9 +5,15 @@ LL | assert_eq!('x'.ipu_flatten(), 0); | ^^^^^^^^^^^ multiple `ipu_flatten` found | = note: candidate #1 is defined in an impl of the trait `inference_unstable_iterator::IpuIterator` for the type `char` - = help: to disambiguate the method call, write `inference_unstable_iterator::IpuIterator::ipu_flatten('x')` instead = note: candidate #2 is defined in an impl of the trait `inference_unstable_itertools::IpuItertools` for the type `char` - = help: to disambiguate the method call, write `inference_unstable_itertools::IpuItertools::ipu_flatten('x')` instead +help: disambiguate the method call for candidate #1 + | +LL | assert_eq!(inference_unstable_iterator::IpuIterator::ipu_flatten(&'x'), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | assert_eq!(inference_unstable_itertools::IpuItertools::ipu_flatten(&'x'), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18446.stderr b/src/test/ui/issues/issue-18446.stderr index e6afc4c13a912..3422add9dd96b 100644 --- a/src/test/ui/issues/issue-18446.stderr +++ b/src/test/ui/issues/issue-18446.stderr @@ -2,7 +2,10 @@ error[E0034]: multiple applicable items in scope --> $DIR/issue-18446.rs:18:7 | LL | x.foo(); - | ^^^ multiple `foo` found + | --^^^-- + | | | + | | multiple `foo` found + | help: disambiguate the method call for candidate #2: `T::foo(&x)` | note: candidate #1 is defined in an impl for the type `dyn T` --> $DIR/issue-18446.rs:9:5 @@ -14,7 +17,6 @@ note: candidate #2 is defined in the trait `T` | LL | fn foo(&self); | ^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `T::foo(&x)` instead error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3702-2.stderr b/src/test/ui/issues/issue-3702-2.stderr index 4d0ff750c254c..b18e407c3d464 100644 --- a/src/test/ui/issues/issue-3702-2.stderr +++ b/src/test/ui/issues/issue-3702-2.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `ToPrimitive` for the type | LL | fn to_int(&self) -> isize { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `ToPrimitive::to_int(&self)` instead note: candidate #2 is defined in an impl of the trait `Add` for the type `isize` --> $DIR/issue-3702-2.rs:14:5 | LL | fn to_int(&self) -> isize { *self } | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Add::to_int(&self)` instead +help: disambiguate the method call for candidate #1 + | +LL | ToPrimitive::to_int(&self) + other.to_int() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | Add::to_int(&self) + other.to_int() + | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr index c7bb653dc1f14..feaf3dc753ffb 100644 --- a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr +++ b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `async::r#struct(r#fn {})` instead note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn` --> $DIR/issue-65634-raw-ident-suggestion.rs:10:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `await::r#struct(r#fn {})` instead +help: disambiguate the method call for candidate #1 + | +LL | async::r#struct(&r#fn {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | await::r#struct(&r#fn {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr index 9f46a722a508e..fa3add81a28f5 100644 --- a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr @@ -9,9 +9,15 @@ note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize` | LL | impl Me2 for usize { fn me(&self) -> usize { *self } } | ^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Me2::me(1_usize)` instead = note: candidate #2 is defined in an impl of the trait `ambig_impl_2_lib::Me` for the type `usize` - = help: to disambiguate the method call, write `ambig_impl_2_lib::Me::me(1_usize)` instead +help: disambiguate the method call for candidate #1 + | +LL | fn main() { Me2::me(&1_usize); } + | ^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | fn main() { ambig_impl_2_lib::Me::me(&1_usize); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr index 6c493c67e29d9..b6c81c2377ee4 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in the trait `A` | LL | trait A { fn foo(&self); } | ^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(t)` instead note: candidate #2 is defined in the trait `B` --> $DIR/method-ambig-two-traits-from-bounds.rs:2:11 | LL | trait B { fn foo(&self); } | ^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(t)` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(t); + | ^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(t); + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr index 0b3724e030fa4..71c65f7ccc68d 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `A` for the type `AB` | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(AB {})` instead note: candidate #2 is defined in an impl of the trait `B` for the type `AB` --> $DIR/method-ambig-two-traits-from-impls.rs:11:5 | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(AB {})` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(AB {}); + | ^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(AB {}); + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr index 81c99b33c813e..55499215799d7 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `A` for the type `AB` | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(...)` instead note: candidate #2 is defined in an impl of the trait `B` for the type `AB` --> $DIR/method-ambig-two-traits-from-impls2.rs:11:5 | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(...)` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(...)(); + | ^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(...)(); + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr index dc8aef2503739..3dbb17371004a 100644 --- a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `usize` | LL | trait Foo { fn method(&self) {} } | ^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Foo::method(1_usize)` instead note: candidate #2 is defined in an impl of the trait `Bar` for the type `usize` --> $DIR/method-ambig-two-traits-with-default-method.rs:6:13 | LL | trait Bar { fn method(&self) {} } | ^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Bar::method(1_usize)` instead +help: disambiguate the method call for candidate #1 + | +LL | Foo::method(&1_usize); + | ^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | Bar::method(&1_usize); + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index c9d7da84e09f4..e7f295df8c482 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -25,19 +25,28 @@ note: candidate #1 is defined in an impl of the trait `internal::X` for the type | LL | fn foo(self: Smaht) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `internal::X::foo(x)` instead note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `_` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9 | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `nuisance_foo::NuisanceFoo::foo(x)` instead note: candidate #3 is defined in the trait `FinalFoo` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5 | LL | fn foo(&self) -> u8; | ^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `FinalFoo::foo(x)` instead +help: disambiguate the method call for candidate #1 + | +LL | let z = internal::X::foo(x); + | ^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | let z = nuisance_foo::NuisanceFoo::foo(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #3 + | +LL | let z = FinalFoo::foo(x); + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:137:24 diff --git a/src/test/ui/span/issue-37767.stderr b/src/test/ui/span/issue-37767.stderr index 0bbff45436c23..9ed6c8b826f79 100644 --- a/src/test/ui/span/issue-37767.stderr +++ b/src/test/ui/span/issue-37767.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in the trait `A` | LL | fn foo(&mut self) {} | ^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(&a)` instead note: candidate #2 is defined in the trait `B` --> $DIR/issue-37767.rs:6:5 | LL | fn foo(&mut self) {} | ^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(&a)` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(&a) + | ^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(&a) + | ^^^^^^^^^^ error[E0034]: multiple applicable items in scope --> $DIR/issue-37767.rs:22:7 @@ -28,13 +34,19 @@ note: candidate #1 is defined in the trait `C` | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `C::foo(&a)` instead note: candidate #2 is defined in the trait `D` --> $DIR/issue-37767.rs:18:5 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `D::foo(&a)` instead +help: disambiguate the method call for candidate #1 + | +LL | C::foo(&a) + | ^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | D::foo(&a) + | ^^^^^^^^^^ error[E0034]: multiple applicable items in scope --> $DIR/issue-37767.rs:34:7 @@ -47,13 +59,19 @@ note: candidate #1 is defined in the trait `E` | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `E::foo(a)` instead note: candidate #2 is defined in the trait `F` --> $DIR/issue-37767.rs:30:5 | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `F::foo(a)` instead +help: disambiguate the method call for candidate #1 + | +LL | E::foo(a) + | ^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | F::foo(a) + | ^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr index 36db5bea86294..53a6238422b57 100644 --- a/src/test/ui/span/issue-7575.stderr +++ b/src/test/ui/span/issue-7575.stderr @@ -10,24 +10,33 @@ note: candidate #1 is defined in the trait `CtxtFn` | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `CtxtFn::f9(u, 342)` instead note: candidate #2 is defined in the trait `OtherTrait` --> $DIR/issue-7575.rs:8:5 | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `OtherTrait::f9(u, 342)` instead note: candidate #3 is defined in the trait `UnusedTrait` --> $DIR/issue-7575.rs:17:5 | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `UnusedTrait::f9(u, 342)` instead = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `f9`, perhaps you need to implement one of them: candidate #1: `CtxtFn` candidate #2: `OtherTrait` candidate #3: `UnusedTrait` +help: disambiguate the method call for candidate #1 + | +LL | u.f8(42) + CtxtFn::f9(u, 342) + m.fff(42) + | ^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | u.f8(42) + OtherTrait::f9(u, 342) + m.fff(42) + | ^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #3 + | +LL | u.f8(42) + UnusedTrait::f9(u, 342) + m.fff(42) + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0599]: no method named `fff` found for type `Myisize` in the current scope --> $DIR/issue-7575.rs:62:30 @@ -60,8 +69,11 @@ note: the candidate is defined in the trait `ManyImplTrait` | LL | fn is_str() -> bool { | ^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `ManyImplTrait::is_str(t)` instead = help: items from traits can only be used if the type parameter is bounded by the trait +help: disambiguate the method call for the candidate + | +LL | ManyImplTrait::is_str(t) + | help: the following trait defines an item `is_str`, perhaps you need to restrict type parameter `T` with it: | LL | fn param_bound(t: T) -> bool { diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr index cde7dd0824924..48a029104aeca 100644 --- a/src/test/ui/traits/trait-alias-ambiguous.stderr +++ b/src/test/ui/traits/trait-alias-ambiguous.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `inner::A::foo(t)` instead note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8` --> $DIR/trait-alias-ambiguous.rs:11:9 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `inner::B::foo(t)` instead +help: disambiguate the method call for candidate #1 + | +LL | inner::A::foo(&t); + | ^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | inner::B::foo(&t); + | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error From 8c4f1d5f875e29e9a6e063744b71dc0a3c7deb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 11 Dec 2019 18:20:29 -0800 Subject: [PATCH 02/18] review comments --- src/librustc_typeck/check/method/suggest.rs | 134 ++++++++++-------- src/test/ui/error-codes/E0034.stderr | 8 +- ...method-ambig-two-traits-from-impls2.stderr | 8 +- 3 files changed, 84 insertions(+), 66 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index cd26e6f237c7d..9cd8c9abfd783 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -15,7 +15,7 @@ use rustc::traits::Obligation; use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; use rustc::ty::print::with_crate_prefix; use syntax_pos::{Span, FileName}; -use syntax::ast; +use syntax::{ast, source_map}; use syntax::util::lev_distance; use rustc_error_codes::*; @@ -79,61 +79,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } - let print_disambiguation_help = | - err: &mut DiagnosticBuilder<'_>, - trait_name: String, - rcvr_ty: Ty<'_>, - kind: ty::AssocKind, - span: Span, - candidate: Option, - | { - let mut applicability = Applicability::MachineApplicable; - let sugg_args = if let ty::AssocKind::Method = kind { - format!( - "({}{})", - if rcvr_ty.is_region_ptr() && args.is_some() { - if rcvr_ty.is_mutable_ptr() { - "&mut " - } else { - "&" - } - } else { - "" - }, - args.map(|arg| arg - .iter() - .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span) - .unwrap_or_else(|_| { - applicability = Applicability::HasPlaceholders; - "...".to_owned() - })) - .collect::>() - .join(", ") - ).unwrap_or_else(|| { - applicability = Applicability::HasPlaceholders; - "...".to_owned() - }), - ) - } else { - String::new() - }; - let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args); - err.span_suggestion( - span, - &format!( - "disambiguate the {} for {}", - kind.suggestion_descr(), - if let Some(candidate) = candidate { - format!("candidate #{}", candidate) - } else { - "the candidate".to_string() - }, - ), - sugg, - applicability, - ); - }; - let report_candidates = | span: Span, err: &mut DiagnosticBuilder<'_>, @@ -215,7 +160,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|ty| *ty) .unwrap_or(rcvr_ty), }; - print_disambiguation_help(err, path, ty, item.kind, sugg_span, idx); + print_disambiguation_help( + item_name, + args, + err, + path, + ty, + item.kind, + sugg_span, + idx, + self.tcx.sess.source_map(), + ); } } CandidateSource::TraitSource(trait_did) => { @@ -244,7 +199,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None }; let path = self.tcx.def_path_str(trait_did); - print_disambiguation_help(err, path, rcvr_ty, item.kind, sugg_span, idx); + print_disambiguation_help( + item_name, + args, + err, + path, + rcvr_ty, + item.kind, + sugg_span, + idx, + self.tcx.sess.source_map(), + ); } } } @@ -1180,3 +1145,56 @@ impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> { hir::intravisit::NestedVisitorMap::None } } + +fn print_disambiguation_help( + item_name: ast::Ident, + args: Option<&'tcx [hir::Expr]>, + err: &mut DiagnosticBuilder<'_>, + trait_name: String, + rcvr_ty: Ty<'_>, + kind: ty::AssocKind, + span: Span, + candidate: Option, + source_map: &source_map::SourceMap, +) { + let mut applicability = Applicability::MachineApplicable; + let sugg_args = if let (ty::AssocKind::Method, Some(args)) = (kind, args) { + format!( + "({}{})", + if rcvr_ty.is_region_ptr() { + if rcvr_ty.is_mutable_ptr() { + "&mut " + } else { + "&" + } + } else { + "" + }, + args.iter() + .map(|arg| source_map.span_to_snippet(arg.span) + .unwrap_or_else(|_| { + applicability = Applicability::HasPlaceholders; + "_".to_owned() + })) + .collect::>() + .join(", "), + ) + } else { + String::new() + }; + let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args); + err.span_suggestion( + span, + &format!( + "disambiguate the {} for {}", + kind.suggestion_descr(), + if let Some(candidate) = candidate { + format!("candidate #{}", candidate) + } else { + "the candidate".to_string() + }, + ), + sugg, + applicability, + ); +} diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr index 30b44fd402bb8..6db2ef5051d83 100644 --- a/src/test/ui/error-codes/E0034.stderr +++ b/src/test/ui/error-codes/E0034.stderr @@ -16,12 +16,12 @@ LL | fn foo() {} | ^^^^^^^^ help: disambiguate the method call for candidate #1 | -LL | Trait1::foo(...)() - | ^^^^^^^^^^^^^^^^ +LL | Trait1::foo() + | ^^^^^^^^^^^ help: disambiguate the method call for candidate #2 | -LL | Trait2::foo(...)() - | ^^^^^^^^^^^^^^^^ +LL | Trait2::foo() + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr index 55499215799d7..44f85071505d2 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr @@ -16,12 +16,12 @@ LL | fn foo() {} | ^^^^^^^^ help: disambiguate the method call for candidate #1 | -LL | A::foo(...)(); - | ^^^^^^^^^^^ +LL | A::foo(); + | ^^^^^^ help: disambiguate the method call for candidate #2 | -LL | B::foo(...)(); - | ^^^^^^^^^^^ +LL | B::foo(); + | ^^^^^^ error: aborting due to previous error From 6ad0b55597d58f65b775cc32588d5cb396993c0c Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Sun, 15 Dec 2019 18:17:00 +0100 Subject: [PATCH 03/18] Remove now-redundant range check on u128 -> f32 casts This code was added to avoid UB in LLVM 6 and earlier, but we no longer support those LLVM versions. Since https://reviews.llvm.org/D47807 (released in LLVM 7), uitofp does exactly what we need. Closes #51872 --- src/librustc_codegen_ssa/mir/rvalue.rs | 43 +++++--------------------- 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 488ae8dbf9036..55d63f18cd906 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -341,6 +341,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llval } } + (CastTy::Int(_), CastTy::Float) => { + if signed { + bx.sitofp(llval, ll_t_out) + } else { + bx.uitofp(llval, ll_t_out) + } + } (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_)) | (CastTy::RPtr(_), CastTy::Ptr(_)) => @@ -352,8 +359,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed); bx.inttoptr(usize_llval, ll_t_out) } - (CastTy::Int(_), CastTy::Float) => - cast_int_to_float(&mut bx, signed, llval, ll_t_in, ll_t_out), (CastTy::Float, CastTy::Int(IntTy::I)) => cast_float_to_int(&mut bx, true, llval, ll_t_in, ll_t_out), (CastTy::Float, CastTy::Int(_)) => @@ -720,40 +725,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } -fn cast_int_to_float<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - signed: bool, - x: Bx::Value, - int_ty: Bx::Type, - float_ty: Bx::Type -) -> Bx::Value { - // Most integer types, even i128, fit into [-f32::MAX, f32::MAX] after rounding. - // It's only u128 -> f32 that can cause overflows (i.e., should yield infinity). - // LLVM's uitofp produces undef in those cases, so we manually check for that case. - let is_u128_to_f32 = !signed && - bx.cx().int_width(int_ty) == 128 && - bx.cx().float_width(float_ty) == 32; - if is_u128_to_f32 { - // All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity, - // and for everything else LLVM's uitofp works just fine. - use rustc_apfloat::ieee::Single; - const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1) - << (Single::MAX_EXP - Single::PRECISION as i16); - let max = bx.cx().const_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP); - let overflow = bx.icmp(IntPredicate::IntUGE, x, max); - let infinity_bits = bx.cx().const_u32(ieee::Single::INFINITY.to_bits() as u32); - let infinity = bx.bitcast(infinity_bits, float_ty); - let fp = bx.uitofp(x, float_ty); - bx.select(overflow, infinity, fp) - } else { - if signed { - bx.sitofp(x, float_ty) - } else { - bx.uitofp(x, float_ty) - } - } -} - fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, signed: bool, From c6321a4df897ab9f32224f493c9e3ee8890cb443 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Fri, 13 Dec 2019 19:14:23 +0100 Subject: [PATCH 04/18] Add benchmarks for string::insert(_str) --- src/liballoc/benches/string.rs | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/liballoc/benches/string.rs b/src/liballoc/benches/string.rs index 2933014cb58e9..599c8b1682851 100644 --- a/src/liballoc/benches/string.rs +++ b/src/liballoc/benches/string.rs @@ -122,3 +122,43 @@ fn bench_to_string(b: &mut Bencher) { Lorem ipsum dolor sit amet, consectetur. "; b.iter(|| s.to_string()) } + +#[bench] +fn bench_insert_char_short(b: &mut Bencher) { + let s = "Hello, World!"; + b.iter(|| { + let mut x = String::from(s); + black_box(&mut x).insert(6, black_box(' ')); + x + }) +} + +#[bench] +fn bench_insert_char_long(b: &mut Bencher) { + let s = "Hello, World!"; + b.iter(|| { + let mut x = String::from(s); + black_box(&mut x).insert(6, black_box('❤')); + x + }) +} + +#[bench] +fn bench_insert_str_short(b: &mut Bencher) { + let s = "Hello, World!"; + b.iter(|| { + let mut x = String::from(s); + black_box(&mut x).insert_str(6, black_box(" ")); + x + }) +} + +#[bench] +fn bench_insert_str_long(b: &mut Bencher) { + let s = "Hello, World!"; + b.iter(|| { + let mut x = String::from(s); + black_box(&mut x).insert_str(6, black_box(" rustic ")); + x + }) +} From c1241bf7a71ed5175274d33516a29f1c4fe5a3a0 Mon Sep 17 00:00:00 2001 From: csmoe Date: Thu, 17 Oct 2019 00:57:18 +0800 Subject: [PATCH 05/18] add debuginfo in generator_interior --- src/librustc/hir/mod.rs | 16 ++++++++++++++++ src/librustc_typeck/check/generator_interior.rs | 12 ++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6b354b01518ea..474b5e33c2a0a 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1857,6 +1857,22 @@ impl fmt::Display for YieldSource { } } +impl core::convert::From for YieldSource { + fn from(gen_kind: GeneratorKind) -> Self { + match gen_kind { + // Guess based on the kind of the current generator. + GeneratorKind::Gen => Self::Yield, + GeneratorKind::Async(_) => Self::Await, + } + } +} + +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] +pub enum CaptureClause { + CaptureByValue, + CaptureByRef, +} + // N.B., if you change this, you'll probably want to change the corresponding // type structure in middle/ty.rs as well. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index fcf6b22f74f3c..35d73d5696431 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -32,7 +32,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { debug!("generator_interior: attempting to record type {:?} {:?} {:?} {:?}", ty, scope, expr, source_span); - let live_across_yield = scope.map(|s| { self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| { // If we are recording an expression that is the last yield @@ -54,15 +53,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { }).unwrap_or_else(|| Some(YieldData { span: DUMMY_SP, expr_and_pat_count: 0, - source: match self.kind { // Guess based on the kind of the current generator. - hir::GeneratorKind::Gen => hir::YieldSource::Yield, - hir::GeneratorKind::Async(_) => hir::YieldSource::Await, - }, + source: self.kind.into(), })); if let Some(yield_data) = live_across_yield { let ty = self.fcx.resolve_vars_if_possible(&ty); - debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}", expr, scope, ty, self.expr_count, yield_data.span); @@ -94,6 +89,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { } else { debug!("no type in expr = {:?}, count = {:?}, span = {:?}", expr, self.expr_count, expr.map(|e| e.span)); + let ty = self.fcx.resolve_vars_if_possible(&ty); + if let Some((unresolved_type, unresolved_type_span)) = self.fcx.unresolved_type_vars(&ty) { + debug!("remained unresolved_type = {:?}, unresolved_type_span: {:?}", + unresolved_type, unresolved_type_span); + } } } } From ff4f6a125891b3474fac1cfd2e86784d4ec073a9 Mon Sep 17 00:00:00 2001 From: csmoe Date: Tue, 22 Oct 2019 02:44:12 +0800 Subject: [PATCH 06/18] record previous unresolve span for generator error reporting --- src/librustc/hir/mod.rs | 12 +++--------- src/librustc_typeck/check/generator_interior.rs | 11 +++++++++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 474b5e33c2a0a..2cffcc5bfade8 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1857,9 +1857,9 @@ impl fmt::Display for YieldSource { } } -impl core::convert::From for YieldSource { - fn from(gen_kind: GeneratorKind) -> Self { - match gen_kind { +impl From for YieldSource { + fn from(kind: GeneratorKind) -> Self { + match kind { // Guess based on the kind of the current generator. GeneratorKind::Gen => Self::Yield, GeneratorKind::Async(_) => Self::Await, @@ -1867,12 +1867,6 @@ impl core::convert::From for YieldSource { } } -#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub enum CaptureClause { - CaptureByValue, - CaptureByRef, -} - // N.B., if you change this, you'll probably want to change the corresponding // type structure in middle/ty.rs as well. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 35d73d5696431..607efca88dd70 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -19,6 +19,7 @@ struct InteriorVisitor<'a, 'tcx> { region_scope_tree: &'tcx region::ScopeTree, expr_count: usize, kind: hir::GeneratorKind, + prev_unresolved_span: Option, } impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { @@ -69,9 +70,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { yield_data.source); // If unresolved type isn't a ty_var then unresolved_type_span is None + let span = self.prev_unresolved_span.unwrap_or_else( + || unresolved_type_span.unwrap_or(source_span) + ); self.fcx.need_type_info_err_in_generator( self.kind, - unresolved_type_span.unwrap_or(source_span), + span, unresolved_type, ) .span_note(yield_data.span, &*note) @@ -90,9 +94,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { debug!("no type in expr = {:?}, count = {:?}, span = {:?}", expr, self.expr_count, expr.map(|e| e.span)); let ty = self.fcx.resolve_vars_if_possible(&ty); - if let Some((unresolved_type, unresolved_type_span)) = self.fcx.unresolved_type_vars(&ty) { + if let Some((unresolved_type, unresolved_type_span)) + = self.fcx.unresolved_type_vars(&ty) { debug!("remained unresolved_type = {:?}, unresolved_type_span: {:?}", unresolved_type, unresolved_type_span); + self.prev_unresolved_span = unresolved_type_span; } } } @@ -112,6 +118,7 @@ pub fn resolve_interior<'a, 'tcx>( region_scope_tree: fcx.tcx.region_scope_tree(def_id), expr_count: 0, kind, + prev_unresolved_span: None, }; intravisit::walk_body(&mut visitor, body); From 17aa0cb2ca73ad789e718bf9162a740af02a829f Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Mon, 25 Nov 2019 14:44:19 -0600 Subject: [PATCH 07/18] Remove a const-if-hack in RawVec --- src/liballoc/raw_vec.rs | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index ee75fc288fee5..dec990a117bf8 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -1,6 +1,8 @@ #![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "0")] #![doc(hidden)] +#![feature(const_if_match)] + use core::cmp; use core::mem; use core::ops::Drop; @@ -51,15 +53,24 @@ pub struct RawVec { impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. + #[cfg(not(bootstrap))] pub const fn new_in(a: A) -> Self { - // `!0` is `usize::MAX`. This branch should be stripped at compile time. - // FIXME(mark-i-m): use this line when `if`s are allowed in `const`: - //let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + let cap = if mem::size_of::() == 0 { !0 } else { 0 }; // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". RawVec { ptr: Unique::empty(), - // FIXME(mark-i-m): use `cap` when ifs are allowed in const + cap, + a, + } + } + + /// Like `new`, but parameterized over the choice of allocator for + /// the returned `RawVec`. + #[cfg(bootstrap)] + pub const fn new_in(a: A) -> Self { + RawVec { + ptr: Unique::empty(), cap: [0, !0][(mem::size_of::() == 0) as usize], a, } @@ -131,17 +142,30 @@ impl RawVec { /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. + #[cfg(not(bootstrap))] pub const fn new() -> Self { // FIXME(Centril): Reintegrate this with `fn new_in` when we can. - // `!0` is `usize::MAX`. This branch should be stripped at compile time. - // FIXME(mark-i-m): use this line when `if`s are allowed in `const`: - //let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + let cap = if mem::size_of::() == 0 { !0 } else { 0 }; // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". RawVec { ptr: Unique::empty(), - // FIXME(mark-i-m): use `cap` when ifs are allowed in const + cap, + a: Global, + } + } + + /// Creates the biggest possible `RawVec` (on the system heap) + /// without allocating. If `T` has positive size, then this makes a + /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a + /// `RawVec` with capacity `usize::MAX`. Useful for implementing + /// delayed allocation. + #[cfg(bootstrap)] + pub const fn new() -> Self { + // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". + RawVec { + ptr: Unique::empty(), cap: [0, !0][(mem::size_of::() == 0) as usize], a: Global, } From 3ec3fca414f62cb3172b9324fe7aaa516c71b4e9 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Mon, 25 Nov 2019 15:29:57 -0600 Subject: [PATCH 08/18] remove a bit more hackery --- src/liballoc/lib.rs | 1 + src/liballoc/raw_vec.rs | 49 +++++++---------------------------------- 2 files changed, 9 insertions(+), 41 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0137275bc1589..6e44c7631b3f0 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -85,6 +85,7 @@ #![feature(const_generic_impls_guard)] #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] +#![cfg_attr(not(bootstrap), feature(const_if_match))] #![feature(cow_is_borrowed)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index dec990a117bf8..ce192a7450c9d 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -1,8 +1,6 @@ #![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "0")] #![doc(hidden)] -#![feature(const_if_match)] - use core::cmp; use core::mem; use core::ops::Drop; @@ -53,9 +51,14 @@ pub struct RawVec { impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. - #[cfg(not(bootstrap))] pub const fn new_in(a: A) -> Self { - let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + let cap = { + #[cfg(not(bootstrap))] + { if mem::size_of::() == 0 { !0 } else { 0 } } + + #[cfg(bootstrap)] + [0, !0][(mem::size_of::() == 0) as usize] + }; // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". RawVec { @@ -65,17 +68,6 @@ impl RawVec { } } - /// Like `new`, but parameterized over the choice of allocator for - /// the returned `RawVec`. - #[cfg(bootstrap)] - pub const fn new_in(a: A) -> Self { - RawVec { - ptr: Unique::empty(), - cap: [0, !0][(mem::size_of::() == 0) as usize], - a, - } - } - /// Like `with_capacity`, but parameterized over the choice of /// allocator for the returned `RawVec`. #[inline] @@ -142,33 +134,8 @@ impl RawVec { /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. - #[cfg(not(bootstrap))] - pub const fn new() -> Self { - // FIXME(Centril): Reintegrate this with `fn new_in` when we can. - - let cap = if mem::size_of::() == 0 { !0 } else { 0 }; - - // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". - RawVec { - ptr: Unique::empty(), - cap, - a: Global, - } - } - - /// Creates the biggest possible `RawVec` (on the system heap) - /// without allocating. If `T` has positive size, then this makes a - /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a - /// `RawVec` with capacity `usize::MAX`. Useful for implementing - /// delayed allocation. - #[cfg(bootstrap)] pub const fn new() -> Self { - // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". - RawVec { - ptr: Unique::empty(), - cap: [0, !0][(mem::size_of::() == 0) as usize], - a: Global, - } + Self::new_in(Global) } /// Creates a `RawVec` (on the system heap) with exactly the From baaf864e07a8b8b99ed548c08606c1c7da74256b Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Mon, 25 Nov 2019 18:14:46 -0600 Subject: [PATCH 09/18] use usize::MAX instead of !0 --- src/liballoc/raw_vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index ce192a7450c9d..0d6fb25957432 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -54,7 +54,7 @@ impl RawVec { pub const fn new_in(a: A) -> Self { let cap = { #[cfg(not(bootstrap))] - { if mem::size_of::() == 0 { !0 } else { 0 } } + { if mem::size_of::() == 0 { usize::MAX } else { 0 } } #[cfg(bootstrap)] [0, !0][(mem::size_of::() == 0) as usize] From 951f041347529e504b132640d829914a0f7ef7c6 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Tue, 26 Nov 2019 11:03:53 -0600 Subject: [PATCH 10/18] fix import --- src/liballoc/raw_vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 0d6fb25957432..dff8364b84730 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -54,7 +54,7 @@ impl RawVec { pub const fn new_in(a: A) -> Self { let cap = { #[cfg(not(bootstrap))] - { if mem::size_of::() == 0 { usize::MAX } else { 0 } } + { if mem::size_of::() == 0 { core::usize::MAX } else { 0 } } #[cfg(bootstrap)] [0, !0][(mem::size_of::() == 0) as usize] From 253543560aa10f90607b23b5b12be3cfe28fdb1b Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Tue, 26 Nov 2019 11:06:53 -0600 Subject: [PATCH 11/18] add fixme --- src/liballoc/raw_vec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index dff8364b84730..96de5185b88cd 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -52,6 +52,7 @@ impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. pub const fn new_in(a: A) -> Self { + // FIXME(mark-i-m): remove bootstrapping cfgs these after a cycle let cap = { #[cfg(not(bootstrap))] { if mem::size_of::() == 0 { core::usize::MAX } else { 0 } } From 7d268119f07aeb41a1abe093c3fd2434743ac228 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Wed, 18 Dec 2019 12:04:47 -0600 Subject: [PATCH 12/18] no need to bootstrap --- src/liballoc/lib.rs | 2 +- src/liballoc/raw_vec.rs | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 6e44c7631b3f0..be46e632be45f 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -85,7 +85,7 @@ #![feature(const_generic_impls_guard)] #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] -#![cfg_attr(not(bootstrap), feature(const_if_match))] +#![feature(const_if_match)] #![feature(cow_is_borrowed)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 96de5185b88cd..3201c702abb29 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -52,14 +52,7 @@ impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. pub const fn new_in(a: A) -> Self { - // FIXME(mark-i-m): remove bootstrapping cfgs these after a cycle - let cap = { - #[cfg(not(bootstrap))] - { if mem::size_of::() == 0 { core::usize::MAX } else { 0 } } - - #[cfg(bootstrap)] - [0, !0][(mem::size_of::() == 0) as usize] - }; + let cap = if mem::size_of::() == 0 { core::usize::MAX } else { 0 }; // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". RawVec { From cbd1e73124dbd35cde4b5cafff127a4e54fef9fe Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 16 Dec 2019 08:52:50 -0500 Subject: [PATCH 13/18] Set release channel on non-dist builders Toolstate publication only runs if the channel is "nightly" and previously the toolstate builders did not know that the channel was nightly (since they are not dist builders). A look through bootstrap seems to indicate that nothing should directly depend on the channel being set to `-dev` on the test builders, though this may cause some problems with UI tests (if for some reason they're dumping the channel into stderr), but we cannot find evidence of such so hopefully this is fine. --- src/bootstrap/toolstate.rs | 6 +++--- src/ci/run.sh | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index a6d9ef38e57b1..b5ebf835506b8 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -13,13 +13,13 @@ use std::env; // Each cycle is 42 days long (6 weeks); the last week is 35..=42 then. const BETA_WEEK_START: u64 = 35; -#[cfg(linux)] +#[cfg(target_os = "linux")] const OS: Option<&str> = Some("linux"); #[cfg(windows)] const OS: Option<&str> = Some("windows"); -#[cfg(all(not(linux), not(windows)))] +#[cfg(all(not(target_os = "linux"), not(windows)))] const OS: Option<&str> = None; type ToolstateData = HashMap, ToolState>; @@ -379,7 +379,7 @@ fn change_toolstate( let mut regressed = false; for repo_state in old_toolstate { let tool = &repo_state.tool; - let state = if cfg!(linux) { + let state = if cfg!(target_os = "linux") { &repo_state.linux } else if cfg!(windows) { &repo_state.windows diff --git a/src/ci/run.sh b/src/ci/run.sh index 38d1d2baf2507..73c3a964f5396 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -44,8 +44,13 @@ fi # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable` # either automatically or manually. export RUST_RELEASE_CHANNEL=nightly + +# Always set the release channel for bootstrap; this is normally not important (i.e., only dist +# builds would seem to matter) but in practice bootstrap wants to know whether we're targeting +# master, beta, or stable with a build to determine whether to run some checks (notably toolstate). +RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL" + if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1" From 35af4e2355f622d19934d3ff2c42991b7cb24324 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sat, 23 Nov 2019 22:33:40 +0800 Subject: [PATCH 14/18] Normalize identifiers in librustc_parse. --- Cargo.lock | 8 ++++++-- src/librustc_parse/Cargo.toml | 1 + src/librustc_parse/lexer/mod.rs | 17 +++++++++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1af0442dde7fc..92219aa170d5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3770,6 +3770,7 @@ dependencies = [ "smallvec 1.0.0", "syntax", "syntax_pos", + "unicode-normalization", ] [[package]] @@ -4976,9 +4977,12 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.7" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" +checksum = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" +dependencies = [ + "smallvec 1.0.0", +] [[package]] name = "unicode-segmentation" diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml index fb5cb742ab651..73458a444f4c6 100644 --- a/src/librustc_parse/Cargo.toml +++ b/src/librustc_parse/Cargo.toml @@ -20,3 +20,4 @@ rustc_error_codes = { path = "../librustc_error_codes" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } syntax_pos = { path = "../libsyntax_pos" } syntax = { path = "../libsyntax" } +unicode-normalization = "0.1.11" diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index ddcfea1898004..31b82bef462fb 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -219,8 +219,7 @@ impl<'a> StringReader<'a> { if is_raw_ident { ident_start = ident_start + BytePos(2); } - // FIXME: perform NFKC normalization here. (Issue #2253) - let sym = self.symbol_from(ident_start); + let sym = self.nfc_symbol_from(ident_start); if is_raw_ident { let span = self.mk_sp(start, self.pos); if !sym.can_be_raw() { @@ -465,6 +464,20 @@ impl<'a> StringReader<'a> { Symbol::intern(self.str_from_to(start, end)) } + /// As symbol_from, with the text normalized into Unicode NFC form. + fn nfc_symbol_from(&self, start: BytePos) -> Symbol { + use unicode_normalization::{is_nfc_quick, IsNormalized, UnicodeNormalization}; + debug!("taking an normalized ident from {:?} to {:?}", start, self.pos); + let sym = self.str_from(start); + match is_nfc_quick(sym.chars()) { + IsNormalized::Yes => Symbol::intern(sym), + _ => { + let sym_str: String = sym.chars().nfc().collect(); + Symbol::intern(&sym_str) + } + } + } + /// Slice of the source text spanning from `start` up to but excluding `end`. fn str_from_to(&self, start: BytePos, end: BytePos) -> &str { From 5a759343fb88d68db984f5f04bf37921474299e1 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sat, 23 Nov 2019 22:37:46 +0800 Subject: [PATCH 15/18] Add a test and bless existing test case. --- src/test/ui/codemap_tests/unicode_2.stderr | 2 +- src/test/ui/rfc-2457/idents-normalized.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/rfc-2457/idents-normalized.rs diff --git a/src/test/ui/codemap_tests/unicode_2.stderr b/src/test/ui/codemap_tests/unicode_2.stderr index 92634d8e5f94c..c01942712d4f3 100644 --- a/src/test/ui/codemap_tests/unicode_2.stderr +++ b/src/test/ui/codemap_tests/unicode_2.stderr @@ -14,7 +14,7 @@ LL | let _ = ("아あ", 1i42); | = help: valid widths are 8, 16, 32, 64 and 128 -error[E0425]: cannot find value `a̐é` in this scope +error[E0425]: cannot find value `a̐é` in this scope --> $DIR/unicode_2.rs:6:13 | LL | let _ = a̐é; diff --git a/src/test/ui/rfc-2457/idents-normalized.rs b/src/test/ui/rfc-2457/idents-normalized.rs new file mode 100644 index 0000000000000..109cec7548e2f --- /dev/null +++ b/src/test/ui/rfc-2457/idents-normalized.rs @@ -0,0 +1,8 @@ +// check-pass +#![feature(non_ascii_idents)] + +struct Résumé; // ['LATIN SMALL LETTER E WITH ACUTE'] + +fn main() { + let _ = Résumé; // ['LATIN SMALL LETTER E', 'COMBINING ACUTE ACCENT'] +} From 49f3bc93ec3b434ab52deaed9678749a6170372f Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Thu, 19 Dec 2019 11:57:30 +0800 Subject: [PATCH 16/18] Add unicode-normalization to whitelist. --- src/tools/tidy/src/deps.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 36e412975b931..d56a016964c03 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -172,6 +172,7 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("term_size"), Crate("thread_local"), Crate("ucd-util"), + Crate("unicode-normalization"), Crate("unicode-width"), Crate("unicode-xid"), Crate("unreachable"), From bfc02bdd3ce81caa8faecb5e5980d177bc165abe Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut <38361244+LeSeulArtichaut@users.noreply.github.com> Date: Thu, 19 Dec 2019 12:58:42 +0100 Subject: [PATCH 17/18] Fix documentation typo --- src/librustc_interface/interface.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index beb2465bd4a1a..2365fc3ee2e4d 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -25,7 +25,7 @@ use syntax_pos::edition; pub type Result = result::Result; /// Represents a compiler session. -/// Can be used run `rustc_interface` queries. +/// Can be used to run `rustc_interface` queries. /// Created by passing `Config` to `run_compiler`. pub struct Compiler { pub(crate) sess: Lrc, From 1787b2b5aba0231ce26a05c4f7a2d6caf8263f0c Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 19 Dec 2019 13:48:36 -0500 Subject: [PATCH 18/18] Fix toolstate history format We were inserting *before* the existing newline, so we should prepend it not append it to our inserted string. --- src/bootstrap/toolstate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index a6d9ef38e57b1..7e547c7799bc1 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -413,7 +413,7 @@ fn change_toolstate( let history_path = format!("rust-toolstate/history/{}.tsv", OS.expect("linux/windows only")); let mut file = t!(fs::read_to_string(&history_path)); let end_of_first_line = file.find('\n').unwrap(); - file.insert_str(end_of_first_line, &format!("{}\t{}\n", commit, toolstate_serialized)); + file.insert_str(end_of_first_line, &format!("\n{}\t{}", commit, toolstate_serialized)); t!(fs::write(&history_path, file)); }