From 577e98521cd042d909278484ab471cd5527485e4 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 8 Nov 2021 19:15:54 +0000 Subject: [PATCH 01/18] Only shown relevant type params in E0283 label When we point at a binding to suggest giving it a type, erase all the type for ADTs that have been resolved, leaving only the ones that could not be inferred. For small shallow types this is not a problem, but for big nested types with lots of params, this can otherwise cause a lot of unnecessary visual output. --- .../infer/error_reporting/need_type_info.rs | 100 +++++++++++++++++- .../defaults/doesnt_infer.stderr | 2 +- .../inference/erase-type-params-in-label.rs | 13 +++ .../erase-type-params-in-label.stderr | 22 ++++ src/test/ui/inference/issue-83606.stderr | 2 +- 5 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/inference/erase-type-params-in-label.rs create mode 100644 src/test/ui/inference/erase-type-params-in-label.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index a7e019a53ee13..dca16548d64dc 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -10,7 +10,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::print::Print; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::symbol::kw; use rustc_span::Span; use std::borrow::Cow; @@ -589,6 +589,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { format!("the explicit type `{}`, with the type parameters specified", ty) } Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => { + let ty = ResolvedTypeParamEraser::new(self.tcx).fold_ty(ty); + let ty = ErrTypeParamEraser(self.tcx).fold_ty(ty); let ty = ty_to_string(ty); format!( "the explicit type `{}`, where the type parameter `{}` is specified", @@ -868,3 +870,99 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err } } + +/// Turn resolved type params into `[type error]` to signal we don't want to display them. +struct ResolvedTypeParamEraser<'tcx> { + tcx: TyCtxt<'tcx>, + level: usize, +} + +impl<'tcx> ResolvedTypeParamEraser<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Self { + ResolvedTypeParamEraser { tcx, level: 0 } + } +} +impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + self.level += 1; + let t = match t.kind() { + // We'll hide this type only if all its type params are hidden as well. + ty::Adt(def, substs) => { + let generics = self.tcx().generics_of(def.did); + // Account for params with default values, like `Vec`, where we + // want to show `Vec`, not `Vec`. If we replaced that + // subst, then we'd get the incorrect output, so we passthrough. + let substs: Vec<_> = substs + .iter() + .zip(generics.params.iter()) + .map(|(subst, param)| match ¶m.kind { + ty::GenericParamDefKind::Type { has_default: true, .. } => subst, + _ => subst.super_fold_with(self), + }) + .collect(); + if self.level == 1 + || substs.iter().any(|subst| match subst.unpack() { + ty::subst::GenericArgKind::Type(t) => match t.kind() { + ty::Error(_) => false, + _ => true, + }, + // Account for `const` params here, otherwise `doesnt_infer.rs` + // shows `_` instead of `Foo<{ _: u32 }>` + ty::subst::GenericArgKind::Const(_) => true, + _ => false, + }) + { + let substs = self.tcx().intern_substs(&substs[..]); + self.tcx().mk_ty(ty::Adt(def, substs)) + } else { + self.tcx().ty_error() + } + } + ty::Ref(_, ty, _) => { + let ty = self.fold_ty(ty); + match ty.kind() { + // Avoid `&_`, these can be safely presented as `_`. + ty::Error(_) => self.tcx().ty_error(), + _ => t.super_fold_with(self), + } + } + // We could account for `()` if we wanted to replace it, but it's assured to be short. + ty::Tuple(_) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Opaque(..) + | ty::Projection(_) + | ty::Never + | ty::Array(..) => t.super_fold_with(self), + // We don't want to hide type params that haven't been resolved yet. + // This would be the type that will be written out with the type param + // name in the output. + ty::Infer(_) => t, + // We don't want to hide the outermost type, only its type params. + _ if self.level == 1 => t.super_fold_with(self), + // Hide this type + _ => self.tcx().ty_error(), + }; + self.level -= 1; + t + } +} + +/// Replace `[type error]` with `ty::Infer(ty::Var)` to display `_`. +struct ErrTypeParamEraser<'tcx>(TyCtxt<'tcx>); +impl<'tcx> TypeFolder<'tcx> for ErrTypeParamEraser<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.0 + } + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.kind() { + ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)), + _ => t.super_fold_with(self), + } + } +} diff --git a/src/test/ui/const-generics/defaults/doesnt_infer.stderr b/src/test/ui/const-generics/defaults/doesnt_infer.stderr index b57975e26f290..183be1b1517a7 100644 --- a/src/test/ui/const-generics/defaults/doesnt_infer.stderr +++ b/src/test/ui/const-generics/defaults/doesnt_infer.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `Foo<{_: u32}>` LL | let foo = Foo::foo(); | --- ^^^^^^^^ cannot infer the value of const parameter `N` | | - | consider giving `foo` the explicit type `Foo<{_: u32}>`, where the type parameter `N` is specified + | consider giving `foo` the explicit type `Foo<{_: _}>`, where the type parameter `N` is specified error: aborting due to previous error diff --git a/src/test/ui/inference/erase-type-params-in-label.rs b/src/test/ui/inference/erase-type-params-in-label.rs new file mode 100644 index 0000000000000..4a163d0b81094 --- /dev/null +++ b/src/test/ui/inference/erase-type-params-in-label.rs @@ -0,0 +1,13 @@ +fn main() { + let foo = new(1, ""); //~ ERROR E0283 +} + +struct Bar { + t: T, + k: K, + n: N, +} + +fn new(t: T, k: K) -> Bar { + Bar { t, k, n: Default::default() } +} diff --git a/src/test/ui/inference/erase-type-params-in-label.stderr b/src/test/ui/inference/erase-type-params-in-label.stderr new file mode 100644 index 0000000000000..b665fade9d88f --- /dev/null +++ b/src/test/ui/inference/erase-type-params-in-label.stderr @@ -0,0 +1,22 @@ +error[E0283]: type annotations needed for `Bar` + --> $DIR/erase-type-params-in-label.rs:2:15 + | +LL | let foo = new(1, ""); + | --- ^^^ cannot infer type for type parameter `Z` declared on the function `new` + | | + | consider giving `foo` the explicit type `Bar<_, _, Z>`, where the type parameter `Z` is specified + | + = note: cannot satisfy `_: Default` +note: required by a bound in `new` + --> $DIR/erase-type-params-in-label.rs:11:17 + | +LL | fn new(t: T, k: K) -> Bar { + | ^^^^^^^ required by this bound in `new` +help: consider specifying the type arguments in the function call + | +LL | let foo = new::(1, ""); + | +++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/inference/issue-83606.stderr b/src/test/ui/inference/issue-83606.stderr index 65f3336b9358a..c66606b9c8304 100644 --- a/src/test/ui/inference/issue-83606.stderr +++ b/src/test/ui/inference/issue-83606.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `[usize; _]` LL | let _ = foo("foo"); //<- Do not suggest `foo::("foo");`! | - ^^^ cannot infer the value of const parameter `N` declared on the function `foo` | | - | consider giving this pattern the explicit type `[usize; _]`, where the type parameter `N` is specified + | consider giving this pattern the explicit type `[_; _]`, where the type parameter `N` is specified error: aborting due to previous error From d0d51ea5ffa8f6301f6d6fc7f17e4d45eeebffcb Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 8 Nov 2021 20:32:17 +0000 Subject: [PATCH 02/18] Refer to uninferred `const` params by their name, instead of `{ _: _ }` When the value of a const param isn't inferred, replace it with the param name from the definition. --- .../infer/error_reporting/need_type_info.rs | 30 +++++++++++++++---- .../defaults/doesnt_infer.stderr | 2 +- src/test/ui/inference/issue-83606.stderr | 2 +- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index dca16548d64dc..b88eebc433dd8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,5 +1,5 @@ use crate::infer::type_variable::TypeVariableOriginKind; -use crate::infer::InferCtxt; +use crate::infer::{InferCtxt, Symbol}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace}; @@ -898,8 +898,17 @@ impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> { let substs: Vec<_> = substs .iter() .zip(generics.params.iter()) - .map(|(subst, param)| match ¶m.kind { - ty::GenericParamDefKind::Type { has_default: true, .. } => subst, + .map(|(subst, param)| match &(subst.unpack(), ¶m.kind) { + (_, ty::GenericParamDefKind::Type { has_default: true, .. }) => subst, + (crate::infer::GenericArgKind::Const(c), _) => { + match c.val { + ty::ConstKind::Infer(..) => { + // Replace not yet inferred const params with their def name. + self.tcx().mk_const_param(param.index, param.name, c.ty).into() + } + _ => subst, + } + } _ => subst.super_fold_with(self), }) .collect(); @@ -937,8 +946,19 @@ impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> { | ty::FnPtr(_) | ty::Opaque(..) | ty::Projection(_) - | ty::Never - | ty::Array(..) => t.super_fold_with(self), + | ty::Never => t.super_fold_with(self), + ty::Array(ty, c) => { + self.tcx().mk_ty(ty::Array( + self.fold_ty(ty), + match c.val { + ty::ConstKind::Infer(..) => { + // Replace not yet inferred const params with their def name. + self.tcx().mk_const_param(0, Symbol::intern("N"), c.ty).into() + } + _ => c, + }, + )) + } // We don't want to hide type params that haven't been resolved yet. // This would be the type that will be written out with the type param // name in the output. diff --git a/src/test/ui/const-generics/defaults/doesnt_infer.stderr b/src/test/ui/const-generics/defaults/doesnt_infer.stderr index 183be1b1517a7..10cd491b480c1 100644 --- a/src/test/ui/const-generics/defaults/doesnt_infer.stderr +++ b/src/test/ui/const-generics/defaults/doesnt_infer.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `Foo<{_: u32}>` LL | let foo = Foo::foo(); | --- ^^^^^^^^ cannot infer the value of const parameter `N` | | - | consider giving `foo` the explicit type `Foo<{_: _}>`, where the type parameter `N` is specified + | consider giving `foo` the explicit type `Foo`, where the type parameter `N` is specified error: aborting due to previous error diff --git a/src/test/ui/inference/issue-83606.stderr b/src/test/ui/inference/issue-83606.stderr index c66606b9c8304..0746b2491fbd6 100644 --- a/src/test/ui/inference/issue-83606.stderr +++ b/src/test/ui/inference/issue-83606.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `[usize; _]` LL | let _ = foo("foo"); //<- Do not suggest `foo::("foo");`! | - ^^^ cannot infer the value of const parameter `N` declared on the function `foo` | | - | consider giving this pattern the explicit type `[_; _]`, where the type parameter `N` is specified + | consider giving this pattern the explicit type `[_; N]`, where the type parameter `N` is specified error: aborting due to previous error From 8a08befa486d4cb0d5d1ba940ab76ed62f39b349 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 8 Nov 2021 21:10:00 +0000 Subject: [PATCH 03/18] Refer to const params as "const params" and not "type params" --- .../infer/error_reporting/need_type_info.rs | 82 +++++++++++-------- .../defaults/doesnt_infer.stderr | 2 +- src/test/ui/inference/issue-83606.stderr | 2 +- 3 files changed, 48 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index b88eebc433dd8..6132bf0556fb4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -10,7 +10,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::print::Print; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder}; +use rustc_middle::ty::{self, Const, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::symbol::kw; use rustc_span::Span; use std::borrow::Cow; @@ -305,6 +305,15 @@ pub enum UnderspecifiedArgKind { Const { is_parameter: bool }, } +impl UnderspecifiedArgKind { + fn descr(&self) -> &'static str { + match self { + Self::Type { .. } => "type", + Self::Const { .. } => "const", + } + } +} + impl InferenceDiagnosticsData { /// Generate a label for a generic argument which can't be inferred. When not /// much is known about the argument, `use_diag` may be used to describe the @@ -548,6 +557,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + let param_type = arg_data.kind.descr(); let suffix = match local_visitor.found_node_ty { Some(ty) if ty.is_closure() => { let substs = @@ -586,15 +596,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => { let ty = ty_to_string(ty); - format!("the explicit type `{}`, with the type parameters specified", ty) + format!("the explicit type `{}`, with the {} parameters specified", ty, param_type) } Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => { let ty = ResolvedTypeParamEraser::new(self.tcx).fold_ty(ty); let ty = ErrTypeParamEraser(self.tcx).fold_ty(ty); let ty = ty_to_string(ty); format!( - "the explicit type `{}`, where the type parameter `{}` is specified", - ty, arg_data.name, + "the explicit type `{}`, where the {} parameter `{}` is specified", + ty, param_type, arg_data.name, ) } _ => "a type".to_string(), @@ -871,7 +881,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } -/// Turn resolved type params into `[type error]` to signal we don't want to display them. +/// Turn *resolved* type params into `[type error]` to signal we don't want to display them. After +/// performing that replacement, we'll turn all remaining infer type params to use their name from +/// their definition, and replace all the `[type error]`s back to being infer so they display in +/// the output as `_`. If we didn't go through `[type error]`, we would either show all type params +/// by their name *or* `_`, neither of which is desireable: we want to show all types that we could +/// infer as `_` to reduce verbosity and avoid telling the user about unnecessary type annotations. struct ResolvedTypeParamEraser<'tcx> { tcx: TyCtxt<'tcx>, level: usize, @@ -881,7 +896,18 @@ impl<'tcx> ResolvedTypeParamEraser<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Self { ResolvedTypeParamEraser { tcx, level: 0 } } + + /// Replace not yet inferred const params with their def name. + fn replace_infers(&self, c: &'tcx Const<'tcx>, index: u32, name: Symbol) -> &'tcx Const<'tcx> { + match c.val { + ty::ConstKind::Infer(..) => { + self.tcx().mk_const_param(index, name, c.ty) + } + _ => c, + } + } } + impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { self.tcx @@ -901,29 +927,22 @@ impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> { .map(|(subst, param)| match &(subst.unpack(), ¶m.kind) { (_, ty::GenericParamDefKind::Type { has_default: true, .. }) => subst, (crate::infer::GenericArgKind::Const(c), _) => { - match c.val { - ty::ConstKind::Infer(..) => { - // Replace not yet inferred const params with their def name. - self.tcx().mk_const_param(param.index, param.name, c.ty).into() - } - _ => subst, - } + self.replace_infers(c, param.index, param.name).into() } _ => subst.super_fold_with(self), }) .collect(); - if self.level == 1 - || substs.iter().any(|subst| match subst.unpack() { - ty::subst::GenericArgKind::Type(t) => match t.kind() { - ty::Error(_) => false, - _ => true, - }, - // Account for `const` params here, otherwise `doesnt_infer.rs` - // shows `_` instead of `Foo<{ _: u32 }>` - ty::subst::GenericArgKind::Const(_) => true, - _ => false, - }) - { + let should_keep = |subst: &GenericArg<'_>| match subst.unpack() { + ty::subst::GenericArgKind::Type(t) => match t.kind() { + ty::Error(_) => false, + _ => true, + }, + // Account for `const` params here, otherwise `doesnt_infer.rs` + // shows `_` instead of `Foo<{ _: u32 }>` + ty::subst::GenericArgKind::Const(_) => true, + _ => false, + }; + if self.level == 1 || substs.iter().any(should_keep) { let substs = self.tcx().intern_substs(&substs[..]); self.tcx().mk_ty(ty::Adt(def, substs)) } else { @@ -947,18 +966,9 @@ impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> { | ty::Opaque(..) | ty::Projection(_) | ty::Never => t.super_fold_with(self), - ty::Array(ty, c) => { - self.tcx().mk_ty(ty::Array( - self.fold_ty(ty), - match c.val { - ty::ConstKind::Infer(..) => { - // Replace not yet inferred const params with their def name. - self.tcx().mk_const_param(0, Symbol::intern("N"), c.ty).into() - } - _ => c, - }, - )) - } + ty::Array(ty, c) => self + .tcx() + .mk_ty(ty::Array(self.fold_ty(ty), self.replace_infers(c, 0, Symbol::intern("N")))), // We don't want to hide type params that haven't been resolved yet. // This would be the type that will be written out with the type param // name in the output. diff --git a/src/test/ui/const-generics/defaults/doesnt_infer.stderr b/src/test/ui/const-generics/defaults/doesnt_infer.stderr index 10cd491b480c1..d6c64d58be5f3 100644 --- a/src/test/ui/const-generics/defaults/doesnt_infer.stderr +++ b/src/test/ui/const-generics/defaults/doesnt_infer.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `Foo<{_: u32}>` LL | let foo = Foo::foo(); | --- ^^^^^^^^ cannot infer the value of const parameter `N` | | - | consider giving `foo` the explicit type `Foo`, where the type parameter `N` is specified + | consider giving `foo` the explicit type `Foo`, where the const parameter `N` is specified error: aborting due to previous error diff --git a/src/test/ui/inference/issue-83606.stderr b/src/test/ui/inference/issue-83606.stderr index 0746b2491fbd6..9ca8f35fd545a 100644 --- a/src/test/ui/inference/issue-83606.stderr +++ b/src/test/ui/inference/issue-83606.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `[usize; _]` LL | let _ = foo("foo"); //<- Do not suggest `foo::("foo");`! | - ^^^ cannot infer the value of const parameter `N` declared on the function `foo` | | - | consider giving this pattern the explicit type `[_; N]`, where the type parameter `N` is specified + | consider giving this pattern the explicit type `[_; N]`, where the const parameter `N` is specified error: aborting due to previous error From e4628193784c0b93d1f04cb8afa3b3a80e9c9349 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 19 Nov 2021 06:10:43 +0000 Subject: [PATCH 04/18] Add test with multiple type params failing inference --- .../infer/error_reporting/need_type_info.rs | 4 +- .../inference/erase-type-params-in-label.rs | 18 ++++++++- .../erase-type-params-in-label.stderr | 39 ++++++++++++++----- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 6132bf0556fb4..124fb11d90080 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -900,9 +900,7 @@ impl<'tcx> ResolvedTypeParamEraser<'tcx> { /// Replace not yet inferred const params with their def name. fn replace_infers(&self, c: &'tcx Const<'tcx>, index: u32, name: Symbol) -> &'tcx Const<'tcx> { match c.val { - ty::ConstKind::Infer(..) => { - self.tcx().mk_const_param(index, name, c.ty) - } + ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty), _ => c, } } diff --git a/src/test/ui/inference/erase-type-params-in-label.rs b/src/test/ui/inference/erase-type-params-in-label.rs index 4a163d0b81094..1fea2da92da94 100644 --- a/src/test/ui/inference/erase-type-params-in-label.rs +++ b/src/test/ui/inference/erase-type-params-in-label.rs @@ -1,5 +1,8 @@ fn main() { - let foo = new(1, ""); //~ ERROR E0283 + let foo = foo(1, ""); //~ ERROR E0283 +} +fn baz() { + let bar = bar(1, ""); //~ ERROR E0283 } struct Bar { @@ -8,6 +11,17 @@ struct Bar { n: N, } -fn new(t: T, k: K) -> Bar { +fn bar(t: T, k: K) -> Bar { Bar { t, k, n: Default::default() } } + +struct Foo { + t: T, + k: K, + n: N, + m: M, +} + +fn foo(t: T, k: K) -> Foo { + Foo { t, k, n: Default::default(), m: Default::default() } +} diff --git a/src/test/ui/inference/erase-type-params-in-label.stderr b/src/test/ui/inference/erase-type-params-in-label.stderr index b665fade9d88f..d0b06cde9d63a 100644 --- a/src/test/ui/inference/erase-type-params-in-label.stderr +++ b/src/test/ui/inference/erase-type-params-in-label.stderr @@ -1,22 +1,41 @@ -error[E0283]: type annotations needed for `Bar` +error[E0283]: type annotations needed for `Foo` --> $DIR/erase-type-params-in-label.rs:2:15 | -LL | let foo = new(1, ""); - | --- ^^^ cannot infer type for type parameter `Z` declared on the function `new` +LL | let foo = foo(1, ""); + | --- ^^^ cannot infer type for type parameter `W` declared on the function `foo` + | | + | consider giving `foo` the explicit type `Foo<_, _, W, Z>`, where the type parameter `W` is specified + | + = note: cannot satisfy `_: Default` +note: required by a bound in `foo` + --> $DIR/erase-type-params-in-label.rs:25:17 + | +LL | fn foo(t: T, k: K) -> Foo { + | ^^^^^^^ required by this bound in `foo` +help: consider specifying the type arguments in the function call + | +LL | let foo = foo::(1, ""); + | ++++++++++++++ + +error[E0283]: type annotations needed for `Bar` + --> $DIR/erase-type-params-in-label.rs:5:15 + | +LL | let bar = bar(1, ""); + | --- ^^^ cannot infer type for type parameter `Z` declared on the function `bar` | | - | consider giving `foo` the explicit type `Bar<_, _, Z>`, where the type parameter `Z` is specified + | consider giving `bar` the explicit type `Bar<_, _, Z>`, where the type parameter `Z` is specified | = note: cannot satisfy `_: Default` -note: required by a bound in `new` - --> $DIR/erase-type-params-in-label.rs:11:17 +note: required by a bound in `bar` + --> $DIR/erase-type-params-in-label.rs:14:17 | -LL | fn new(t: T, k: K) -> Bar { - | ^^^^^^^ required by this bound in `new` +LL | fn bar(t: T, k: K) -> Bar { + | ^^^^^^^ required by this bound in `bar` help: consider specifying the type arguments in the function call | -LL | let foo = new::(1, ""); +LL | let bar = bar::(1, ""); | +++++++++++ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0283`. From d6e34ad108dc998e9f9d872e807e221c0df4f24b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 15 Jul 2021 08:36:19 -0700 Subject: [PATCH 05/18] When recovering from a `:` in a pattern, use adequate AST pattern --- compiler/rustc_parse/src/parser/pat.rs | 103 +++++++++++++++--- .../issues/issue-87086-colon-path-sep.rs | 31 ++++-- .../issues/issue-87086-colon-path-sep.stderr | 60 ++++++---- 3 files changed, 150 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index bb3947bb47a25..c1f5c569cf09f 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -3,13 +3,17 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::token; -use rustc_ast::{self as ast, AttrVec, Attribute, MacCall, Pat, PatField, PatKind, RangeEnd}; -use rustc_ast::{BindingMode, Expr, ExprKind, Mutability, Path, QSelf, RangeSyntax}; +use rustc_ast::{ + self as ast, AttrVec, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat, + PatField, PatKind, Path, PathSegment, QSelf, RangeEnd, RangeSyntax, +}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult}; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; +use std::mem::take; + type Expected = Option<&'static str>; /// `Expected` for function and lambda parameter patterns. @@ -101,11 +105,8 @@ impl<'a> Parser<'a> { let mut first_pat = first_pat; if let (RecoverColon::Yes, token::Colon) = (ra, &self.token.kind) { - if matches!( - first_pat.kind, - PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) - | PatKind::Path(..) - ) && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) + if matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) + && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) { // The pattern looks like it might be a path with a `::` -> `:` typo: // `match foo { bar:baz => {} }` @@ -126,17 +127,87 @@ impl<'a> Parser<'a> { err.cancel(); *self = snapshot; } - Ok(pat) => { + Ok(mut pat) => { // We've parsed the rest of the pattern. - err.span_suggestion( - span, - "maybe write a path separator here", - "::".to_string(), - Applicability::MachineApplicable, - ); + let new_span = first_pat.span.to(pat.span); + let mut show_sugg = false; + match &mut pat.kind { + PatKind::Struct(qself @ None, path, ..) + | PatKind::TupleStruct(qself @ None, path, _) + | PatKind::Path(qself @ None, path) => { + match &first_pat.kind { + PatKind::Ident(_, ident, _) => { + path.segments.insert( + 0, + PathSegment::from_ident(ident.clone()), + ); + path.span = new_span; + show_sugg = true; + first_pat = pat; + } + PatKind::Path(old_qself, old_path) => { + path.segments = old_path + .segments + .iter() + .cloned() + .chain(take(&mut path.segments)) + .collect(); + path.span = new_span; + *qself = old_qself.clone(); + first_pat = pat; + show_sugg = true; + } + _ => {} + } + } + PatKind::Ident( + BindingMode::ByValue(Mutability::Not), + ident, + None, + ) => match &first_pat.kind { + PatKind::Ident(_, old_ident, _) => { + let path = PatKind::Path( + None, + Path { + span: new_span, + segments: vec![ + PathSegment::from_ident( + old_ident.clone(), + ), + PathSegment::from_ident(ident.clone()), + ], + tokens: None, + }, + ); + first_pat = self.mk_pat(new_span, path); + show_sugg = true; + } + PatKind::Path(old_qself, old_path) => { + let mut segments = old_path.segments.clone(); + segments + .push(PathSegment::from_ident(ident.clone())); + let path = PatKind::Path( + old_qself.clone(), + Path { span: new_span, segments, tokens: None }, + ); + first_pat = self.mk_pat(new_span, path); + show_sugg = true; + } + _ => {} + }, + _ => {} + } + if show_sugg { + err.span_suggestion( + span, + "maybe write a path separator here", + "::".to_string(), + Applicability::MachineApplicable, + ); + } else { + first_pat = self.mk_pat(new_span, PatKind::Wild); + } err.emit(); - first_pat = - self.mk_pat(first_pat.span.to(pat.span), PatKind::Wild); } } } diff --git a/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs b/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs index 4ee0b2054ff77..0b7b67496d6f3 100644 --- a/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs +++ b/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs @@ -1,11 +1,15 @@ // Tests that a suggestion is issued if the user wrote a colon instead of // a path separator in a match arm. -enum Foo { - Bar, - Baz, +mod qux { + pub enum Foo { + Bar, + Baz, + } } +use qux::Foo; + fn f() -> Foo { Foo::Bar } fn g1() { @@ -16,24 +20,24 @@ fn g1() { _ => {} } match f() { - Foo::Bar:Baz => {} + qux::Foo:Bar => {} //~^ ERROR: expected one of //~| HELP: maybe write a path separator here _ => {} } match f() { - Foo:Bar::Baz => {} + qux:Foo::Baz => {} //~^ ERROR: expected one of //~| HELP: maybe write a path separator here _ => {} } match f() { - Foo: Bar::Baz if true => {} + qux: Foo::Baz if true => {} //~^ ERROR: expected one of //~| HELP: maybe write a path separator here _ => {} } - if let Bar:Baz = f() { + if let Foo:Bar = f() { //~^ ERROR: expected one of //~| HELP: maybe write a path separator here } @@ -41,16 +45,18 @@ fn g1() { fn g1_neg() { match f() { - ref Foo: Bar::Baz => {} + ref qux: Foo::Baz => {} //~^ ERROR: expected one of + //~| HELP: maybe write a path separator here _ => {} } } fn g2_neg() { match f() { - mut Foo: Bar::Baz => {} + mut qux: Foo::Baz => {} //~^ ERROR: expected one of + //~| HELP: maybe write a path separator here _ => {} } } @@ -62,5 +68,12 @@ fn main() { Foo:Bar::Baz => {} //~^ ERROR: expected one of //~| HELP: maybe write a path separator here + //~| ERROR: failed to resolve: `Bar` is a variant, not a module + } + match myfoo { + Foo::Bar => {} + Foo:Bar => {} + //~^ ERROR: expected one of + //~| HELP: maybe write a path separator here } } diff --git a/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr b/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr index 8f93661a62646..2050a16beb349 100644 --- a/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr +++ b/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr @@ -1,5 +1,5 @@ error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:13:12 + --> $DIR/issue-87086-colon-path-sep.rs:17:12 | LL | Foo:Bar => {} | ^ @@ -8,55 +8,61 @@ LL | Foo:Bar => {} | help: maybe write a path separator here: `::` error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:19:17 + --> $DIR/issue-87086-colon-path-sep.rs:23:17 | -LL | Foo::Bar:Baz => {} +LL | qux::Foo:Bar => {} | ^ | | | expected one of 8 possible tokens | help: maybe write a path separator here: `::` error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:25:12 + --> $DIR/issue-87086-colon-path-sep.rs:29:12 | -LL | Foo:Bar::Baz => {} +LL | qux:Foo::Baz => {} | ^ | | | expected one of `@` or `|` | help: maybe write a path separator here: `::` error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:31:12 + --> $DIR/issue-87086-colon-path-sep.rs:35:12 | -LL | Foo: Bar::Baz if true => {} +LL | qux: Foo::Baz if true => {} | ^ | | | expected one of `@` or `|` | help: maybe write a path separator here: `::` error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:36:15 + --> $DIR/issue-87086-colon-path-sep.rs:40:15 | -LL | if let Bar:Baz = f() { +LL | if let Foo:Bar = f() { | ^ | | | expected one of `@` or `|` | help: maybe write a path separator here: `::` -error: expected one of `=>`, `@`, `if`, or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:44:16 +error: expected one of `@` or `|`, found `:` + --> $DIR/issue-87086-colon-path-sep.rs:48:16 | -LL | ref Foo: Bar::Baz => {} - | ^ expected one of `=>`, `@`, `if`, or `|` +LL | ref qux: Foo::Baz => {} + | ^ + | | + | expected one of `@` or `|` + | help: maybe write a path separator here: `::` -error: expected one of `=>`, `@`, `if`, or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:52:16 +error: expected one of `@` or `|`, found `:` + --> $DIR/issue-87086-colon-path-sep.rs:57:16 | -LL | mut Foo: Bar::Baz => {} - | ^ expected one of `=>`, `@`, `if`, or `|` +LL | mut qux: Foo::Baz => {} + | ^ + | | + | expected one of `@` or `|` + | help: maybe write a path separator here: `::` error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:62:12 + --> $DIR/issue-87086-colon-path-sep.rs:68:12 | LL | Foo:Bar::Baz => {} | ^ @@ -64,5 +70,21 @@ LL | Foo:Bar::Baz => {} | expected one of `@` or `|` | help: maybe write a path separator here: `::` -error: aborting due to 8 previous errors +error: expected one of `@` or `|`, found `:` + --> $DIR/issue-87086-colon-path-sep.rs:75:12 + | +LL | Foo:Bar => {} + | ^ + | | + | expected one of `@` or `|` + | help: maybe write a path separator here: `::` + +error[E0433]: failed to resolve: `Bar` is a variant, not a module + --> $DIR/issue-87086-colon-path-sep.rs:68:13 + | +LL | Foo:Bar::Baz => {} + | ^^^ `Bar` is a variant, not a module + +error: aborting due to 10 previous errors +For more information about this error, try `rustc --explain E0433`. From eeaa215f85b17756d68e41615f0f69fdf9802058 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Thu, 25 Nov 2021 21:16:27 -0500 Subject: [PATCH 06/18] Don't treat unnormalized function arguments as well-formed --- .../src/type_check/free_region_relations.rs | 6 ++-- .../rustc_typeck/src/check/compare_method.rs | 7 +---- compiler/rustc_typeck/src/check/mod.rs | 1 - compiler/rustc_typeck/src/check/wfcheck.rs | 5 ---- .../implied-bounds-unnorm-associated-type.rs | 22 ++++++++++++++ ...plied-bounds-unnorm-associated-type.stderr | 13 ++++++++ .../generic-associated-types/issue-87748.rs | 30 ------------------- 7 files changed, 38 insertions(+), 46 deletions(-) create mode 100644 src/test/ui/fn/implied-bounds-unnorm-associated-type.rs create mode 100644 src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr delete mode 100644 src/test/ui/generic-associated-types/issue-87748.rs diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index f71cf09ecf630..8d97c3cbb0b0e 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -256,7 +256,6 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { debug!("build: input_or_output={:?}", ty); // We add implied bounds from both the unnormalized and normalized ty // See issue #87748 - let constraints_implied_1 = self.add_implied_bounds(ty); let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self .param_env .and(type_op::normalize::Normalize::new(ty)) @@ -284,10 +283,9 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { // } // ``` // Both &Self::Bar and &() are WF - let constraints_implied_2 = - if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None }; + let constraints_implied = self.add_implied_bounds(norm_ty); normalized_inputs_and_output.push(norm_ty); - constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2) + constraints1.into_iter().chain(constraints_implied) }) .collect(); diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 3eadb3f2363d2..e7e36f11e750d 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -266,14 +266,9 @@ fn compare_predicate_entailment<'tcx>( // First liberate late bound regions and subst placeholders let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id)); let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs); - // Next, add all inputs and output as well-formed tys. Importantly, - // we have to do this before normalization, since the normalized ty may - // not contain the input parameters. See issue #87748. - wf_tys.extend(trait_sig.inputs_and_output.iter()); let trait_sig = inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig); - // Also add the resulting inputs and output as well-formed. - // This probably isn't strictly necessary. + // Add the resulting inputs and output as well-formed. wf_tys.extend(trait_sig.inputs_and_output.iter()); let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 7450b4a4ef1c3..a037bb6647825 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -391,7 +391,6 @@ fn typeck_with_fallback<'tcx>( let mut wf_tys = FxHashSet::default(); // Compute the fty from point of view of inside the fn. let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); - wf_tys.extend(fn_sig.inputs_and_output.iter()); let fn_sig = inh.normalize_associated_types_in( body.value.span, body_id.hir_id, diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index c1adc2894ccfc..1c48d91f91a9f 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1322,11 +1322,6 @@ fn check_fn_or_method<'fcx, 'tcx>( ) { let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig); - // Unnormalized types in signature are WF too - implied_bounds.extend(sig.inputs()); - // FIXME(#27579) return types should not be implied bounds - implied_bounds.insert(sig.output()); - // Normalize the input and output types one at a time, using a different // `WellFormedLoc` for each. We cannot call `normalize_associated_types` // on the entire `FnSig`, since this would use the same `WellFormedLoc` diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs new file mode 100644 index 0000000000000..2e5ac7d7398eb --- /dev/null +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs @@ -0,0 +1,22 @@ +// check-fail +// See issue #91068. Types in the substs of an associated type can't be implied +// to be WF, since they don't actually have to be constructed. + +trait Trait { + type Type; +} + +impl Trait for T { + type Type = (); +} + +fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str { + s //~ ERROR lifetime mismatch [E0623] +} + +fn main() { + let x = String::from("Hello World!"); + let y = f(&x, ()); + drop(x); + println!("{}", y); +} diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr new file mode 100644 index 0000000000000..93ab5dceee947 --- /dev/null +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr @@ -0,0 +1,13 @@ +error[E0623]: lifetime mismatch + --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5 + | +LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str { + | ------- ---------- + | | + | these two types are declared with different lifetimes... +LL | s + | ^ ...but data from `s` flows here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/generic-associated-types/issue-87748.rs b/src/test/ui/generic-associated-types/issue-87748.rs deleted file mode 100644 index 93c3b3937cb81..0000000000000 --- a/src/test/ui/generic-associated-types/issue-87748.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Checks that we properly add implied bounds from unnormalized projections in -// inputs when typechecking functions. - -// check-pass - -#![feature(generic_associated_types)] - -trait MyTrait { - type Assoc<'a, 'b> where 'b: 'a; - fn do_sth(arg: Self::Assoc<'_, '_>); -} - -struct A; -struct B; -struct C; - -impl MyTrait for A { - type Assoc<'a, 'b> where 'b: 'a = u32; - fn do_sth(_: u32) {} -} -impl MyTrait for B { - type Assoc<'a, 'b> where 'b: 'a = u32; - fn do_sth(_: Self::Assoc<'_, '_>) {} -} -impl MyTrait for C { - type Assoc<'a, 'b> where 'b: 'a = u32; - fn do_sth(_: Self::Assoc<'static, 'static>) {} -} - -fn main () {} From df3e7a28f77170bcdb9d8860d6c4a06a7cdfbe20 Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Fri, 26 Nov 2021 22:51:09 +1100 Subject: [PATCH 07/18] Refactor EmitterWriter::emit_suggestion_default --- compiler/rustc_errors/src/emitter.rs | 39 ++++++++++++++++++---------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index d64a589bd9b2a..c04246a5022e8 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -214,7 +214,7 @@ pub trait Emitter { /// Formats the substitutions of the primary_span /// - /// The are a lot of conditions to this method, but in short: + /// There are a lot of conditions to this method, but in short: /// /// * If the current `Diagnostic` has only one visible `CodeSuggestion`, /// we format the `help` suggestion depending on the content of the @@ -736,7 +736,9 @@ impl EmitterWriter { let line_offset = buffer.num_lines(); - let left = margin.left(source_string.len()); // Left trim + // Left trim + let left = margin.left(source_string.len()); + // Account for unicode characters of width !=0 that were removed. let left = source_string .chars() @@ -1623,18 +1625,27 @@ impl EmitterWriter { suggestions.iter().take(MAX_SUGGESTIONS) { notice_capitalization |= only_capitalization; - // Only show underline if the suggestion spans a single line and doesn't cover the - // entirety of the code output. If you have multiple replacements in the same line - // of code, show the underline. - let show_underline = !(parts.len() == 1 && parts[0].snippet.trim() == complete.trim()) - && complete.lines().count() == 1; let has_deletion = parts.iter().any(|p| p.is_deletion()); let is_multiline = complete.lines().count() > 1; - let show_diff = has_deletion && !is_multiline; + enum DisplaySuggestion { + Underline, + Diff, + None, + } + + let show_code_change = if has_deletion && !is_multiline { + DisplaySuggestion::Diff + } else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim()) + && !is_multiline + { + DisplaySuggestion::Underline + } else { + DisplaySuggestion::None + }; - if show_diff { + if let DisplaySuggestion::Diff = show_code_change { row_num += 1; } @@ -1657,7 +1668,7 @@ impl EmitterWriter { &self.maybe_anonymized(line_start + line_pos), Style::LineNumber, ); - if show_diff { + if let DisplaySuggestion::Diff = show_code_change { // Add the line number for both addition and removal to drive the point home. // // N - fn foo(bar: A) { @@ -1727,7 +1738,7 @@ impl EmitterWriter { let mut offsets: Vec<(usize, isize)> = Vec::new(); // Only show an underline in the suggestions if the suggestion is not the // entirety of the code being shown and the displayed code is not multiline. - if show_underline { + if let DisplaySuggestion::Diff | DisplaySuggestion::Underline = show_code_change { draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); for part in parts { let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display; @@ -1755,7 +1766,7 @@ impl EmitterWriter { assert!(underline_start >= 0 && underline_end >= 0); let padding: usize = max_line_num_len + 3; for p in underline_start..underline_end { - if !show_diff { + if let DisplaySuggestion::Underline = show_code_change { // If this is a replacement, underline with `^`, if this is an addition // underline with `+`. buffer.putc( @@ -1766,7 +1777,7 @@ impl EmitterWriter { ); } } - if show_diff { + if let DisplaySuggestion::Diff = show_code_change { // Colorize removal with red in diff format. buffer.set_style_range( row_num - 2, @@ -1797,7 +1808,7 @@ impl EmitterWriter { // if we elided some lines, add an ellipsis if lines.next().is_some() { buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); - } else if !show_underline { + } else if let DisplaySuggestion::None = show_code_change { draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1); row_num += 1; } From b6f9416863f9c818a60ba44e279197a111400503 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 28 Nov 2021 23:05:54 +0800 Subject: [PATCH 08/18] tests: Ignore `test/debuginfo/rc_arc.rs` on windows-gnu The tests checks some pretty-printer output, but pretty-printers are not embedded on windows-gnu --- src/test/debuginfo/rc_arc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/debuginfo/rc_arc.rs b/src/test/debuginfo/rc_arc.rs index 144a746062daa..8470ace24b845 100644 --- a/src/test/debuginfo/rc_arc.rs +++ b/src/test/debuginfo/rc_arc.rs @@ -1,4 +1,4 @@ -// pretty-printers are not loaded +// ignore-windows-gnu: pretty-printers are not loaded // compile-flags:-g // min-gdb-version: 8.1 From e500eb69508a6e65880db3618399c89ed276f34e Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 28 Nov 2021 17:53:50 -0500 Subject: [PATCH 09/18] Bump compiler_builtins to 0.1.55 to bring in fixes for targets lacking atomic support. --- Cargo.lock | 4 ++-- library/std/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2536c5cda119..2233162be3b6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -678,9 +678,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.53" +version = "0.1.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2467ff455350a4df7d02f1ed1449d0279605a763de5d586dcf6aa7d732508bcb" +checksum = "c9ac60765140c97aaf531dae151a287646b0805ec725805da9e2a3ee31cd501c" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index b43445f2eed5c..f711174832142 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -16,7 +16,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } libc = { version = "0.2.108", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.53" } +compiler_builtins = { version = "0.1.55" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] } From 3c42a11895224c0e8c1b37ea0ba77adc03ed2f63 Mon Sep 17 00:00:00 2001 From: kijima Date: Tue, 30 Nov 2021 01:31:10 +0900 Subject: [PATCH 10/18] Fix small typo --- compiler/rustc_errors/src/emitter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index d64a589bd9b2a..467ba9755f905 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2083,7 +2083,7 @@ const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[ ('\t', " "), // We do our own tab replacement ('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters. ('\u{202A}', ""), // The following unicode text flow control characters are inconsistently - ('\u{202B}', ""), // supported accross CLIs and can cause confusion due to the bytes on disk + ('\u{202B}', ""), // supported across CLIs and can cause confusion due to the bytes on disk ('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always. ('\u{202E}', ""), ('\u{2066}', ""), From 6c3c3e0952b63cfae51392863e94d79c2d76deb9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Nov 2021 13:00:37 -0500 Subject: [PATCH 11/18] CTFE: support assert_zero_valid and assert_uninit_valid --- .../src/interpret/intrinsics.rs | 26 ++++++++++++- library/core/src/intrinsics.rs | 2 + src/test/ui/consts/assert-type-intrinsics.rs | 22 +++++++++++ .../ui/consts/assert-type-intrinsics.stderr | 39 +++++++++++++++++++ src/test/ui/consts/assume-type-intrinsics.rs | 13 ------- .../ui/consts/assume-type-intrinsics.stderr | 15 ------- 6 files changed, 88 insertions(+), 29 deletions(-) create mode 100644 src/test/ui/consts/assert-type-intrinsics.rs create mode 100644 src/test/ui/consts/assert-type-intrinsics.stderr delete mode 100644 src/test/ui/consts/assume-type-intrinsics.rs delete mode 100644 src/test/ui/consts/assume-type-intrinsics.stderr diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 44da27a43db0a..025d2998b0052 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -394,10 +394,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::transmute => { self.copy_op_transmute(&args[0], dest)?; } - sym::assert_inhabited => { + sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { let ty = instance.substs.type_at(0); let layout = self.layout_of(ty)?; + // For *all* intrinsics we first check `is_uninhabited` to give a more specific + // error message. if layout.abi.is_uninhabited() { // The run-time intrinsic panics just to get a good backtrace; here we abort // since there is no problem showing a backtrace even for aborts. @@ -409,6 +411,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ), )?; } + if intrinsic_name == sym::assert_zero_valid + && !layout.might_permit_raw_init(self, /*zero:*/ true) + { + M::abort( + self, + format!( + "aborted execution: attempted to zero-initialize type `{}`, which is invalid", + ty + ), + )?; + } + if intrinsic_name == sym::assert_uninit_valid + && !layout.might_permit_raw_init(self, /*zero:*/ false) + { + M::abort( + self, + format!( + "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", + ty + ), + )?; + } } sym::simd_insert => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 23b28766d70ea..edbc250eb0d0c 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -860,12 +860,14 @@ extern "rust-intrinsic" { /// zero-initialization: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")] pub fn assert_zero_valid(); /// A guard for unsafe functions that cannot ever be executed if `T` has invalid /// bit patterns: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")] pub fn assert_uninit_valid(); /// Gets a reference to a static `Location` indicating where it was called. diff --git a/src/test/ui/consts/assert-type-intrinsics.rs b/src/test/ui/consts/assert-type-intrinsics.rs new file mode 100644 index 0000000000000..31ff6aed03b2f --- /dev/null +++ b/src/test/ui/consts/assert-type-intrinsics.rs @@ -0,0 +1,22 @@ +// error-pattern: any use of this value will cause an error + +#![feature(never_type)] +#![feature(const_maybe_uninit_assume_init, const_assert_type2)] +#![feature(core_intrinsics)] + +use std::intrinsics; + +#[allow(invalid_value)] +fn main() { + use std::mem::MaybeUninit; + + const _BAD1: () = unsafe { + MaybeUninit::::uninit().assume_init(); + }; + const _BAD2: () = unsafe { + intrinsics::assert_uninit_valid::(); + }; + const _BAD3: () = unsafe { + intrinsics::assert_zero_valid::<&'static i32>(); + }; +} diff --git a/src/test/ui/consts/assert-type-intrinsics.stderr b/src/test/ui/consts/assert-type-intrinsics.stderr new file mode 100644 index 0000000000000..bb57ee82cc16f --- /dev/null +++ b/src/test/ui/consts/assert-type-intrinsics.stderr @@ -0,0 +1,39 @@ +error: any use of this value will cause an error + --> $DIR/assert-type-intrinsics.rs:14:9 + | +LL | / const _BAD1: () = unsafe { +LL | | MaybeUninit::::uninit().assume_init(); + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` +LL | | }; + | |______- + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + +error: any use of this value will cause an error + --> $DIR/assert-type-intrinsics.rs:17:9 + | +LL | / const _BAD2: () = unsafe { +LL | | intrinsics::assert_uninit_valid::(); + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid +LL | | }; + | |______- + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + +error: any use of this value will cause an error + --> $DIR/assert-type-intrinsics.rs:20:9 + | +LL | / const _BAD3: () = unsafe { +LL | | intrinsics::assert_zero_valid::<&'static i32>(); + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid +LL | | }; + | |______- + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/consts/assume-type-intrinsics.rs b/src/test/ui/consts/assume-type-intrinsics.rs deleted file mode 100644 index 77370e1ccc59e..0000000000000 --- a/src/test/ui/consts/assume-type-intrinsics.rs +++ /dev/null @@ -1,13 +0,0 @@ -// error-pattern: any use of this value will cause an error - -#![feature(never_type)] -#![feature(const_maybe_uninit_assume_init)] - -#[allow(invalid_value)] -fn main() { - use std::mem::MaybeUninit; - - const _BAD: () = unsafe { - MaybeUninit::::uninit().assume_init(); - }; -} diff --git a/src/test/ui/consts/assume-type-intrinsics.stderr b/src/test/ui/consts/assume-type-intrinsics.stderr deleted file mode 100644 index e660730396fa1..0000000000000 --- a/src/test/ui/consts/assume-type-intrinsics.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: any use of this value will cause an error - --> $DIR/assume-type-intrinsics.rs:11:9 - | -LL | / const _BAD: () = unsafe { -LL | | MaybeUninit::::uninit().assume_init(); - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` -LL | | }; - | |______- - | - = note: `#[deny(const_err)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 - -error: aborting due to previous error - From dec0d83b4160f52a8b0dfc049ced903b2c4e10e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 29 Nov 2021 18:53:28 +0200 Subject: [PATCH 12/18] :arrow_up: rust-analyzer --- src/tools/rust-analyzer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 183ef048f61ae..d9b2291f546ab 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 183ef048f61ae36aa389d1d0345cde940fe788e9 +Subproject commit d9b2291f546abc77d24499339a72a89127464b95 From c02710530c0005a30759e170be023cc167c6cd67 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Sun, 21 Nov 2021 04:56:32 +0000 Subject: [PATCH 13/18] review comments: clean up --- .../rustc_parse/src/parser/diagnostics.rs | 182 +++++++++++++++++- compiler/rustc_parse/src/parser/pat.rs | 176 +---------------- 2 files changed, 185 insertions(+), 173 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ce39d07656f2a..55af2c9ddd32f 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1,6 +1,9 @@ +use super::pat::Expected; use super::ty::AllowPlus; -use super::TokenType; -use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType}; +use super::{ + BlockMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, SemiColonMode, SeqSep, + TokenExpectType, TokenType, +}; use rustc_ast as ast; use rustc_ast::ptr::P; @@ -19,6 +22,8 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident}; use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP}; +use std::mem::take; + use tracing::{debug, trace}; const TURBOFISH_SUGGESTION_STR: &str = @@ -2075,4 +2080,177 @@ impl<'a> Parser<'a> { ); err } + + /// Some special error handling for the "top-level" patterns in a match arm, + /// `for` loop, `let`, &c. (in contrast to subpatterns within such). + crate fn maybe_recover_colon_colon_in_pat_typo( + &mut self, + mut first_pat: P, + ra: RecoverColon, + expected: Expected, + ) -> P { + if RecoverColon::Yes != ra || token::Colon != self.token.kind { + return first_pat; + } + if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) + || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) + { + return first_pat; + } + // The pattern looks like it might be a path with a `::` -> `:` typo: + // `match foo { bar:baz => {} }` + let span = self.token.span; + // We only emit "unexpected `:`" error here if we can successfully parse the + // whole pattern correctly in that case. + let snapshot = self.clone(); + + // Create error for "unexpected `:`". + match self.expected_one_of_not_found(&[], &[]) { + Err(mut err) => { + self.bump(); // Skip the `:`. + match self.parse_pat_no_top_alt(expected) { + Err(mut inner_err) => { + // Carry on as if we had not done anything, callers will emit a + // reasonable error. + inner_err.cancel(); + err.cancel(); + *self = snapshot; + } + Ok(mut pat) => { + // We've parsed the rest of the pattern. + let new_span = first_pat.span.to(pat.span); + let mut show_sugg = false; + // Try to construct a recovered pattern. + match &mut pat.kind { + PatKind::Struct(qself @ None, path, ..) + | PatKind::TupleStruct(qself @ None, path, _) + | PatKind::Path(qself @ None, path) => match &first_pat.kind { + PatKind::Ident(_, ident, _) => { + path.segments.insert(0, PathSegment::from_ident(ident.clone())); + path.span = new_span; + show_sugg = true; + first_pat = pat; + } + PatKind::Path(old_qself, old_path) => { + path.segments = old_path + .segments + .iter() + .cloned() + .chain(take(&mut path.segments)) + .collect(); + path.span = new_span; + *qself = old_qself.clone(); + first_pat = pat; + show_sugg = true; + } + _ => {} + }, + PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => { + match &first_pat.kind { + PatKind::Ident(_, old_ident, _) => { + let path = PatKind::Path( + None, + Path { + span: new_span, + segments: vec![ + PathSegment::from_ident(old_ident.clone()), + PathSegment::from_ident(ident.clone()), + ], + tokens: None, + }, + ); + first_pat = self.mk_pat(new_span, path); + show_sugg = true; + } + PatKind::Path(old_qself, old_path) => { + let mut segments = old_path.segments.clone(); + segments.push(PathSegment::from_ident(ident.clone())); + let path = PatKind::Path( + old_qself.clone(), + Path { span: new_span, segments, tokens: None }, + ); + first_pat = self.mk_pat(new_span, path); + show_sugg = true; + } + _ => {} + } + } + _ => {} + } + if show_sugg { + err.span_suggestion( + span, + "maybe write a path separator here", + "::".to_string(), + Applicability::MaybeIncorrect, + ); + } else { + first_pat = self.mk_pat(new_span, PatKind::Wild); + } + err.emit(); + } + } + } + _ => { + // Carry on as if we had not done anything. This should be unreachable. + *self = snapshot; + } + }; + first_pat + } + + /// Some special error handling for the "top-level" patterns in a match arm, + /// `for` loop, `let`, &c. (in contrast to subpatterns within such). + crate fn maybe_recover_unexpected_comma( + &mut self, + lo: Span, + rc: RecoverComma, + ) -> PResult<'a, ()> { + if rc == RecoverComma::No || self.token != token::Comma { + return Ok(()); + } + + // An unexpected comma after a top-level pattern is a clue that the + // user (perhaps more accustomed to some other language) forgot the + // parentheses in what should have been a tuple pattern; return a + // suggestion-enhanced error here rather than choking on the comma later. + let comma_span = self.token.span; + self.bump(); + if let Err(mut err) = self.skip_pat_list() { + // We didn't expect this to work anyway; we just wanted to advance to the + // end of the comma-sequence so we know the span to suggest parenthesizing. + err.cancel(); + } + let seq_span = lo.to(self.prev_token.span); + let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); + if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { + const MSG: &str = "try adding parentheses to match on a tuple..."; + + err.span_suggestion( + seq_span, + MSG, + format!("({})", seq_snippet), + Applicability::MachineApplicable, + ); + err.span_suggestion( + seq_span, + "...or a vertical bar to match on multiple alternatives", + seq_snippet.replace(",", " |"), + Applicability::MachineApplicable, + ); + } + Err(err) + } + + /// Parse and throw away a parenthesized comma separated + /// sequence of patterns until `)` is reached. + fn skip_pat_list(&mut self) -> PResult<'a, ()> { + while !self.check(&token::CloseDelim(token::Paren)) { + self.parse_pat_no_top_alt(None)?; + if !self.eat(&token::Comma) { + return Ok(()); + } + } + Ok(()) + } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index c1f5c569cf09f..ac3123c40e3d9 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -5,16 +5,14 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::{ self as ast, AttrVec, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat, - PatField, PatKind, Path, PathSegment, QSelf, RangeEnd, RangeSyntax, + PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, }; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult}; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; -use std::mem::take; - -type Expected = Option<&'static str>; +pub(super) type Expected = Option<&'static str>; /// `Expected` for function and lambda parameter patterns. pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); @@ -102,122 +100,9 @@ impl<'a> Parser<'a> { // If we parsed a leading `|` which should be gated, // then we should really gate the leading `|`. // This complicated procedure is done purely for diagnostics UX. - let mut first_pat = first_pat; - if let (RecoverColon::Yes, token::Colon) = (ra, &self.token.kind) { - if matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) - && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) - { - // The pattern looks like it might be a path with a `::` -> `:` typo: - // `match foo { bar:baz => {} }` - let span = self.token.span; - // We only emit "unexpected `:`" error here if we can successfully parse the - // whole pattern correctly in that case. - let snapshot = self.clone(); - - // Create error for "unexpected `:`". - match self.expected_one_of_not_found(&[], &[]) { - Err(mut err) => { - self.bump(); // Skip the `:`. - match self.parse_pat_no_top_alt(expected) { - Err(mut inner_err) => { - // Carry on as if we had not done anything, callers will emit a - // reasonable error. - inner_err.cancel(); - err.cancel(); - *self = snapshot; - } - Ok(mut pat) => { - // We've parsed the rest of the pattern. - let new_span = first_pat.span.to(pat.span); - let mut show_sugg = false; - match &mut pat.kind { - PatKind::Struct(qself @ None, path, ..) - | PatKind::TupleStruct(qself @ None, path, _) - | PatKind::Path(qself @ None, path) => { - match &first_pat.kind { - PatKind::Ident(_, ident, _) => { - path.segments.insert( - 0, - PathSegment::from_ident(ident.clone()), - ); - path.span = new_span; - show_sugg = true; - first_pat = pat; - } - PatKind::Path(old_qself, old_path) => { - path.segments = old_path - .segments - .iter() - .cloned() - .chain(take(&mut path.segments)) - .collect(); - path.span = new_span; - *qself = old_qself.clone(); - first_pat = pat; - show_sugg = true; - } - _ => {} - } - } - PatKind::Ident( - BindingMode::ByValue(Mutability::Not), - ident, - None, - ) => match &first_pat.kind { - PatKind::Ident(_, old_ident, _) => { - let path = PatKind::Path( - None, - Path { - span: new_span, - segments: vec![ - PathSegment::from_ident( - old_ident.clone(), - ), - PathSegment::from_ident(ident.clone()), - ], - tokens: None, - }, - ); - first_pat = self.mk_pat(new_span, path); - show_sugg = true; - } - PatKind::Path(old_qself, old_path) => { - let mut segments = old_path.segments.clone(); - segments - .push(PathSegment::from_ident(ident.clone())); - let path = PatKind::Path( - old_qself.clone(), - Path { span: new_span, segments, tokens: None }, - ); - first_pat = self.mk_pat(new_span, path); - show_sugg = true; - } - _ => {} - }, - _ => {} - } - if show_sugg { - err.span_suggestion( - span, - "maybe write a path separator here", - "::".to_string(), - Applicability::MachineApplicable, - ); - } else { - first_pat = self.mk_pat(new_span, PatKind::Wild); - } - err.emit(); - } - } - } - _ => { - // Carry on as if we had not done anything. This should be unreachable. - *self = snapshot; - } - }; - } - } + // Check if the user wrote `foo:bar` instead of `foo::bar`. + let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected); if let Some(leading_vert_span) = leading_vert_span { // If there was a leading vert, treat this as an or-pattern. This improves @@ -392,57 +277,6 @@ impl<'a> Parser<'a> { err.emit(); } - /// Some special error handling for the "top-level" patterns in a match arm, - /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> { - if rc == RecoverComma::No || self.token != token::Comma { - return Ok(()); - } - - // An unexpected comma after a top-level pattern is a clue that the - // user (perhaps more accustomed to some other language) forgot the - // parentheses in what should have been a tuple pattern; return a - // suggestion-enhanced error here rather than choking on the comma later. - let comma_span = self.token.span; - self.bump(); - if let Err(mut err) = self.skip_pat_list() { - // We didn't expect this to work anyway; we just wanted to advance to the - // end of the comma-sequence so we know the span to suggest parenthesizing. - err.cancel(); - } - let seq_span = lo.to(self.prev_token.span); - let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); - if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { - const MSG: &str = "try adding parentheses to match on a tuple..."; - - err.span_suggestion( - seq_span, - MSG, - format!("({})", seq_snippet), - Applicability::MachineApplicable, - ); - err.span_suggestion( - seq_span, - "...or a vertical bar to match on multiple alternatives", - seq_snippet.replace(",", " |"), - Applicability::MachineApplicable, - ); - } - Err(err) - } - - /// Parse and throw away a parenthesized comma separated - /// sequence of patterns until `)` is reached. - fn skip_pat_list(&mut self) -> PResult<'a, ()> { - while !self.check(&token::CloseDelim(token::Paren)) { - self.parse_pat_no_top_alt(None)?; - if !self.eat(&token::Comma) { - return Ok(()); - } - } - Ok(()) - } - /// A `|` or possibly `||` token shouldn't be here. Ban it. fn ban_illegal_vert(&mut self, lo: Option, pos: &str, ctx: &str) { let span = self.token.span; @@ -1239,7 +1073,7 @@ impl<'a> Parser<'a> { self.mk_pat(span, PatKind::Ident(bm, ident, None)) } - fn mk_pat(&self, span: Span, kind: PatKind) -> P { + pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> P { P(Pat { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) } } From f67e73ab95a3052353a6761216f53bae22ce2c7a Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 26 Nov 2021 19:18:51 +0000 Subject: [PATCH 14/18] Factor out build reduced graph for extern crate --- .../rustc_resolve/src/build_reduced_graph.rs | 152 ++++++++++-------- 1 file changed, 83 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3cf9d324a38da..02e540e2091f5 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -683,75 +683,16 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } ItemKind::ExternCrate(orig_name) => { - let module = if orig_name.is_none() && ident.name == kw::SelfLower { - self.r - .session - .struct_span_err(item.span, "`extern crate self;` requires renaming") - .span_suggestion( - item.span, - "try", - "extern crate self as name;".into(), - Applicability::HasPlaceholders, - ) - .emit(); - return; - } else if orig_name == Some(kw::SelfLower) { - self.r.graph_root - } else { - let crate_id = self.r.crate_loader.process_extern_crate( - item, - &self.r.definitions, - local_def_id, - ); - self.r.extern_crate_map.insert(local_def_id, crate_id); - self.r.expect_module(crate_id.as_def_id()) - }; - - let used = self.process_macro_use_imports(item, module); - let binding = - (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); - let import = self.r.arenas.alloc_import(Import { - kind: ImportKind::ExternCrate { source: orig_name, target: ident }, - root_id: item.id, - id: item.id, - parent_scope: self.parent_scope, - imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), - has_attributes: !item.attrs.is_empty(), - use_span_with_attributes: item.span_with_attributes(), - use_span: item.span, - root_span: item.span, - span: item.span, - module_path: Vec::new(), - vis: Cell::new(vis), - used: Cell::new(used), - }); - self.r.potentially_unused_imports.push(import); - let imported_binding = self.r.import(binding, import); - if ptr::eq(parent, self.r.graph_root) { - if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) - { - if expansion != LocalExpnId::ROOT - && orig_name.is_some() - && entry.extern_crate_item.is_none() - { - let msg = "macro-expanded `extern crate` items cannot \ - shadow names passed with `--extern`"; - self.r.session.span_err(item.span, msg); - } - } - let entry = - self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert( - ExternPreludeEntry { - extern_crate_item: None, - introduced_by_item: true, - }, - ); - entry.extern_crate_item = Some(imported_binding); - if orig_name.is_some() { - entry.introduced_by_item = true; - } - } - self.r.define(parent, ident, TypeNS, imported_binding); + self.build_reduced_graph_for_extern_crate( + orig_name, + ident, + item, + local_def_id, + sp, + expansion, + vis, + parent, + ); } ItemKind::Mod(..) => { @@ -889,6 +830,79 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } } + fn build_reduced_graph_for_extern_crate( + &mut self, + orig_name: Option, + ident: Ident, + item: &Item, + local_def_id: LocalDefId, + sp: Span, + expansion: LocalExpnId, + vis: ty::Visibility, + parent: Module<'a>, + ) { + let module = if orig_name.is_none() && ident.name == kw::SelfLower { + self.r + .session + .struct_span_err(item.span, "`extern crate self;` requires renaming") + .span_suggestion( + item.span, + "try", + "extern crate self as name;".into(), + Applicability::HasPlaceholders, + ) + .emit(); + return; + } else if orig_name == Some(kw::SelfLower) { + self.r.graph_root + } else { + let crate_id = + self.r.crate_loader.process_extern_crate(item, &self.r.definitions, local_def_id); + self.r.extern_crate_map.insert(local_def_id, crate_id); + self.r.expect_module(crate_id.as_def_id()) + }; + let used = self.process_macro_use_imports(item, module); + let binding = + (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); + let import = self.r.arenas.alloc_import(Import { + kind: ImportKind::ExternCrate { source: orig_name, target: ident }, + root_id: item.id, + id: item.id, + parent_scope: self.parent_scope, + imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), + has_attributes: !item.attrs.is_empty(), + use_span_with_attributes: item.span_with_attributes(), + use_span: item.span, + root_span: item.span, + span: item.span, + module_path: Vec::new(), + vis: Cell::new(vis), + used: Cell::new(used), + }); + self.r.potentially_unused_imports.push(import); + let imported_binding = self.r.import(binding, import); + if ptr::eq(parent, self.r.graph_root) { + if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) { + if expansion != LocalExpnId::ROOT + && orig_name.is_some() + && entry.extern_crate_item.is_none() + { + let msg = "macro-expanded `extern crate` items cannot \ + shadow names passed with `--extern`"; + self.r.session.span_err(item.span, msg); + } + } + let entry = self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert( + ExternPreludeEntry { extern_crate_item: None, introduced_by_item: true }, + ); + entry.extern_crate_item = Some(imported_binding); + if orig_name.is_some() { + entry.introduced_by_item = true; + } + } + self.r.define(parent, ident, TypeNS, imported_binding); + } + /// Constructs the reduced graph for one foreign item. fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) { let local_def_id = self.r.local_def_id(item.id); From 29b4b6cbc84f7ee784461fcb6e39c60a5ab5effc Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 26 Nov 2021 20:37:56 +0000 Subject: [PATCH 15/18] Stop treating extern crate loading failures as fatal errors --- compiler/rustc_metadata/src/creader.rs | 38 +++++++++++------ compiler/rustc_metadata/src/locator.rs | 22 +++++----- .../rustc_resolve/src/build_reduced_graph.rs | 41 ++++++++++++++----- compiler/rustc_resolve/src/imports.rs | 6 ++- src/test/ui/crate-loading/missing-std.rs | 1 + src/test/ui/crate-loading/missing-std.stderr | 6 ++- .../ui/extern-flag/empty-extern-arg.stderr | 6 ++- .../extern/extern-crate-multiple-missing.rs | 8 ++++ .../extern-crate-multiple-missing.stderr | 15 +++++++ src/test/ui/issues/issue-37131.stderr | 4 +- .../issue-49851/compiler-builtins-error.rs | 6 ++- .../compiler-builtins-error.stderr | 12 +++++- 12 files changed, 124 insertions(+), 41 deletions(-) create mode 100644 src/test/ui/extern/extern-crate-multiple-missing.rs create mode 100644 src/test/ui/extern/extern-crate-multiple-missing.stderr diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index eb0a693226c48..f3e7d84c1c530 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -9,6 +9,7 @@ use rustc_ast::{self as ast, *}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; +use rustc_errors::FatalError; use rustc_expand::base::SyntaxExtension; use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; @@ -507,18 +508,31 @@ impl<'a> CrateLoader<'a> { })) } - fn resolve_crate<'b>( + fn resolve_crate_or_abort<'b>( &'b mut self, name: Symbol, span: Span, dep_kind: CrateDepKind, ) -> CrateNum { + self.resolve_crate(name, span, dep_kind).unwrap_or_else(|| FatalError.raise()) + } + + fn resolve_crate<'b>( + &'b mut self, + name: Symbol, + span: Span, + dep_kind: CrateDepKind, + ) -> Option { self.used_extern_options.insert(name); - self.maybe_resolve_crate(name, dep_kind, None).unwrap_or_else(|err| { - let missing_core = - self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err(); - err.report(&self.sess, span, missing_core) - }) + self.maybe_resolve_crate(name, dep_kind, None).map_or_else( + |err| { + let missing_core = + self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err(); + err.report(&self.sess, span, missing_core); + None + }, + |cnum| Some(cnum), + ) } fn maybe_resolve_crate<'b>( @@ -751,7 +765,7 @@ impl<'a> CrateLoader<'a> { }; info!("panic runtime not found -- loading {}", name); - let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit); + let cnum = self.resolve_crate_or_abort(name, DUMMY_SP, CrateDepKind::Implicit); let data = self.cstore.get_crate_data(cnum); // Sanity check the loaded crate to ensure it is indeed a panic runtime @@ -791,7 +805,7 @@ impl<'a> CrateLoader<'a> { ); } - let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit); + let cnum = self.resolve_crate_or_abort(name, DUMMY_SP, CrateDepKind::Implicit); let data = self.cstore.get_crate_data(cnum); // Sanity check the loaded crate to ensure it is indeed a profiler runtime @@ -991,7 +1005,7 @@ impl<'a> CrateLoader<'a> { item: &ast::Item, definitions: &Definitions, def_id: LocalDefId, - ) -> CrateNum { + ) -> Option { match item.kind { ast::ItemKind::ExternCrate(orig_name) => { debug!( @@ -1011,7 +1025,7 @@ impl<'a> CrateLoader<'a> { CrateDepKind::Explicit }; - let cnum = self.resolve_crate(name, item.span, dep_kind); + let cnum = self.resolve_crate(name, item.span, dep_kind)?; let path_len = definitions.def_path(def_id).data.len(); self.update_extern_crate( @@ -1023,14 +1037,14 @@ impl<'a> CrateLoader<'a> { dependency_of: LOCAL_CRATE, }, ); - cnum + Some(cnum) } _ => bug!(), } } pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> CrateNum { - let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit); + let cnum = self.resolve_crate_or_abort(name, span, CrateDepKind::Explicit); self.update_extern_crate( cnum, diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 7cba16e0a9ae3..03181012bccb7 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -220,7 +220,7 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; -use rustc_errors::struct_span_err; +use rustc_errors::{struct_span_err, DiagnosticBuilder, FatalError}; use rustc_session::config::{self, CrateType}; use rustc_session::cstore::{CrateSource, MetadataLoader}; use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch}; @@ -814,11 +814,11 @@ pub fn find_plugin_registrar( span: Span, name: Symbol, ) -> PathBuf { - match find_plugin_registrar_impl(sess, metadata_loader, name) { - Ok(res) => res, + find_plugin_registrar_impl(sess, metadata_loader, name).unwrap_or_else(|err| { // `core` is always available if we got as far as loading plugins. - Err(err) => err.report(sess, span, false), - } + err.report(sess, span, false); + FatalError.raise() + }) } fn find_plugin_registrar_impl<'a>( @@ -931,8 +931,8 @@ impl fmt::Display for MetadataError<'_> { } impl CrateError { - crate fn report(self, sess: &Session, span: Span, missing_core: bool) -> ! { - let mut err = match self { + fn build_diag(self, sess: &Session, span: Span, missing_core: bool) -> DiagnosticBuilder<'_> { + match self { CrateError::NonAsciiName(crate_name) => sess.struct_span_err( span, &format!("cannot load a crate with a non-ascii name `{}`", crate_name), @@ -1208,10 +1208,10 @@ impl CrateError { "plugin `{}` only found in rlib format, but must be available in dylib format", crate_name, ), - }; + } + } - err.emit(); - sess.abort_if_errors(); - unreachable!(); + crate fn report(self, sess: &Session, span: Span, missing_core: bool) { + self.build_diag(sess, span, missing_core).emit(); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 02e540e2091f5..aaa946f75421b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -685,11 +685,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ItemKind::ExternCrate(orig_name) => { self.build_reduced_graph_for_extern_crate( orig_name, - ident, item, local_def_id, - sp, - expansion, vis, parent, ); @@ -833,14 +830,16 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn build_reduced_graph_for_extern_crate( &mut self, orig_name: Option, - ident: Ident, item: &Item, local_def_id: LocalDefId, - sp: Span, - expansion: LocalExpnId, vis: ty::Visibility, parent: Module<'a>, ) { + let ident = item.ident; + let sp = item.span; + let parent_scope = self.parent_scope; + let expansion = parent_scope.expansion; + let module = if orig_name.is_none() && ident.name == kw::SelfLower { self.r .session @@ -856,10 +855,32 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } else if orig_name == Some(kw::SelfLower) { self.r.graph_root } else { - let crate_id = - self.r.crate_loader.process_extern_crate(item, &self.r.definitions, local_def_id); - self.r.extern_crate_map.insert(local_def_id, crate_id); - self.r.expect_module(crate_id.as_def_id()) + match self.r.crate_loader.process_extern_crate(item, &self.r.definitions, local_def_id) + { + Some(crate_id) => { + self.r.extern_crate_map.insert(local_def_id, crate_id); + self.r.expect_module(crate_id.as_def_id()) + } + _ => { + let dummy_import = self.r.arenas.alloc_import(Import { + kind: ImportKind::ExternCrate { source: orig_name, target: ident }, + root_id: item.id, + id: item.id, + parent_scope: self.parent_scope, + imported_module: Cell::new(None), + has_attributes: !item.attrs.is_empty(), + use_span_with_attributes: item.span_with_attributes(), + use_span: item.span, + root_span: item.span, + span: item.span, + module_path: Vec::new(), + vis: Cell::new(vis), + used: Cell::new(true), + }); + self.r.import_dummy_binding(dummy_import); + return; + } + } }; let used = self.process_macro_use_imports(item, module); let binding = diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index bf4cece8bde8d..d2c64b7e4418d 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -600,8 +600,10 @@ impl<'a> Resolver<'a> { // Define a "dummy" resolution containing a Res::Err as a placeholder for a // failed resolution - fn import_dummy_binding(&mut self, import: &'a Import<'a>) { - if let ImportKind::Single { target, .. } = import.kind { + crate fn import_dummy_binding(&mut self, import: &'a Import<'a>) { + if let ImportKind::Single { target, .. } | ImportKind::ExternCrate { target, .. } = + import.kind + { let dummy_binding = self.dummy_binding; let dummy_binding = self.import(dummy_binding, import); self.per_ns(|this, ns| { diff --git a/src/test/ui/crate-loading/missing-std.rs b/src/test/ui/crate-loading/missing-std.rs index 1a34c21ba5413..400d9f6e0ba12 100644 --- a/src/test/ui/crate-loading/missing-std.rs +++ b/src/test/ui/crate-loading/missing-std.rs @@ -1,6 +1,7 @@ // compile-flags: --target x86_64-unknown-uefi // needs-llvm-components: x86 // rustc-env:CARGO=/usr/bin/cargo +#![feature(no_core)] #![no_core] extern crate core; //~^ ERROR can't find crate for `core` diff --git a/src/test/ui/crate-loading/missing-std.stderr b/src/test/ui/crate-loading/missing-std.stderr index 25808efdfa699..70bcae1e0edd0 100644 --- a/src/test/ui/crate-loading/missing-std.stderr +++ b/src/test/ui/crate-loading/missing-std.stderr @@ -1,5 +1,5 @@ error[E0463]: can't find crate for `core` - --> $DIR/missing-std.rs:5:1 + --> $DIR/missing-std.rs:6:1 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ can't find crate @@ -8,6 +8,8 @@ LL | extern crate core; = help: consider downloading the target with `rustup target add x86_64-unknown-uefi` = help: consider building the standard library from source with `cargo build -Zbuild-std` -error: aborting due to previous error +error: requires `sized` lang_item + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0463`. diff --git a/src/test/ui/extern-flag/empty-extern-arg.stderr b/src/test/ui/extern-flag/empty-extern-arg.stderr index 199c4fb616b53..b0628a4f6dd62 100644 --- a/src/test/ui/extern-flag/empty-extern-arg.stderr +++ b/src/test/ui/extern-flag/empty-extern-arg.stderr @@ -1,4 +1,8 @@ error: extern location for std does not exist: -error: aborting due to previous error +error: language item required, but not found: `eh_personality` + +error: `#[panic_handler]` function required, but not found + +error: aborting due to 3 previous errors diff --git a/src/test/ui/extern/extern-crate-multiple-missing.rs b/src/test/ui/extern/extern-crate-multiple-missing.rs new file mode 100644 index 0000000000000..fa7da83a6dfef --- /dev/null +++ b/src/test/ui/extern/extern-crate-multiple-missing.rs @@ -0,0 +1,8 @@ +// If multiple `extern crate` resolutions fail each of them should produce an error +extern crate bar; //~ ERROR can't find crate for `bar` +extern crate foo; //~ ERROR can't find crate for `foo` + +fn main() { + foo::something(); + bar::something(); +} diff --git a/src/test/ui/extern/extern-crate-multiple-missing.stderr b/src/test/ui/extern/extern-crate-multiple-missing.stderr new file mode 100644 index 0000000000000..893bb4fb26d0d --- /dev/null +++ b/src/test/ui/extern/extern-crate-multiple-missing.stderr @@ -0,0 +1,15 @@ +error[E0463]: can't find crate for `bar` + --> $DIR/extern-crate-multiple-missing.rs:2:1 + | +LL | extern crate bar; + | ^^^^^^^^^^^^^^^^^ can't find crate + +error[E0463]: can't find crate for `foo` + --> $DIR/extern-crate-multiple-missing.rs:3:1 + | +LL | extern crate foo; + | ^^^^^^^^^^^^^^^^^ can't find crate + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0463`. diff --git a/src/test/ui/issues/issue-37131.stderr b/src/test/ui/issues/issue-37131.stderr index b45574f0c49af..9ecae3e7a2b24 100644 --- a/src/test/ui/issues/issue-37131.stderr +++ b/src/test/ui/issues/issue-37131.stderr @@ -4,6 +4,8 @@ error[E0463]: can't find crate for `std` = help: consider downloading the target with `rustup target add thumbv6m-none-eabi` = help: consider building the standard library from source with `cargo build -Zbuild-std` -error: aborting due to previous error +error: requires `sized` lang_item + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0463`. diff --git a/src/test/ui/issues/issue-49851/compiler-builtins-error.rs b/src/test/ui/issues/issue-49851/compiler-builtins-error.rs index ddb070ddf9fae..4e56cca33d6a9 100644 --- a/src/test/ui/issues/issue-49851/compiler-builtins-error.rs +++ b/src/test/ui/issues/issue-49851/compiler-builtins-error.rs @@ -1,4 +1,5 @@ -//~ ERROR 1:1: 1:1: can't find crate for `core` [E0463] +//~ ERROR can't find crate for `core` +//~^ ERROR can't find crate for `compiler_builtins` // compile-flags: --target thumbv7em-none-eabihf // needs-llvm-components: arm @@ -7,3 +8,6 @@ #![no_std] extern crate cortex_m; +//~^ ERROR can't find crate for `cortex_m` + +fn main() {} diff --git a/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr b/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr index d963c07ea9175..fcfa2bf119cff 100644 --- a/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr +++ b/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr @@ -4,6 +4,16 @@ error[E0463]: can't find crate for `core` = help: consider downloading the target with `rustup target add thumbv7em-none-eabihf` = help: consider building the standard library from source with `cargo build -Zbuild-std` -error: aborting due to previous error +error[E0463]: can't find crate for `compiler_builtins` + +error[E0463]: can't find crate for `cortex_m` + --> $DIR/compiler-builtins-error.rs:10:1 + | +LL | extern crate cortex_m; + | ^^^^^^^^^^^^^^^^^^^^^^ can't find crate + +error: requires `sized` lang_item + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0463`. From 2c9d9b4b758a9d6bdae212852c59d71a3edcc5de Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 26 Nov 2021 21:39:44 +0000 Subject: [PATCH 16/18] Improve suggestion for extern crate self error message --- compiler/rustc_metadata/src/creader.rs | 30 ++++-------- compiler/rustc_metadata/src/locator.rs | 12 ++--- .../rustc_resolve/src/build_reduced_graph.rs | 48 +++++++------------ compiler/rustc_resolve/src/imports.rs | 6 +-- compiler/rustc_resolve/src/lib.rs | 4 +- src/test/ui/crate-loading/invalid-rlib.rs | 2 + src/test/ui/crate-loading/invalid-rlib.stderr | 10 +++- .../extern/extern-crate-multiple-missing.rs | 2 + .../extern-crate-self-fail.stderr | 7 ++- .../ui/rust-2018/uniform-paths/deadlock.rs | 3 +- .../rust-2018/uniform-paths/deadlock.stderr | 21 ++++++-- 11 files changed, 75 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f3e7d84c1c530..2626a2e189c1d 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -9,7 +9,6 @@ use rustc_ast::{self as ast, *}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; -use rustc_errors::FatalError; use rustc_expand::base::SyntaxExtension; use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; @@ -508,15 +507,6 @@ impl<'a> CrateLoader<'a> { })) } - fn resolve_crate_or_abort<'b>( - &'b mut self, - name: Symbol, - span: Span, - dep_kind: CrateDepKind, - ) -> CrateNum { - self.resolve_crate(name, span, dep_kind).unwrap_or_else(|| FatalError.raise()) - } - fn resolve_crate<'b>( &'b mut self, name: Symbol, @@ -524,15 +514,15 @@ impl<'a> CrateLoader<'a> { dep_kind: CrateDepKind, ) -> Option { self.used_extern_options.insert(name); - self.maybe_resolve_crate(name, dep_kind, None).map_or_else( - |err| { + match self.maybe_resolve_crate(name, dep_kind, None) { + Ok(cnum) => Some(cnum), + Err(err) => { let missing_core = self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err(); err.report(&self.sess, span, missing_core); None - }, - |cnum| Some(cnum), - ) + } + } } fn maybe_resolve_crate<'b>( @@ -765,7 +755,7 @@ impl<'a> CrateLoader<'a> { }; info!("panic runtime not found -- loading {}", name); - let cnum = self.resolve_crate_or_abort(name, DUMMY_SP, CrateDepKind::Implicit); + let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; }; let data = self.cstore.get_crate_data(cnum); // Sanity check the loaded crate to ensure it is indeed a panic runtime @@ -805,7 +795,7 @@ impl<'a> CrateLoader<'a> { ); } - let cnum = self.resolve_crate_or_abort(name, DUMMY_SP, CrateDepKind::Implicit); + let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; }; let data = self.cstore.get_crate_data(cnum); // Sanity check the loaded crate to ensure it is indeed a profiler runtime @@ -1043,8 +1033,8 @@ impl<'a> CrateLoader<'a> { } } - pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> CrateNum { - let cnum = self.resolve_crate_or_abort(name, span, CrateDepKind::Explicit); + pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option { + let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?; self.update_extern_crate( cnum, @@ -1057,7 +1047,7 @@ impl<'a> CrateLoader<'a> { }, ); - cnum + Some(cnum) } pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option { diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 03181012bccb7..e2fd8056f1a7c 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -220,7 +220,7 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; -use rustc_errors::{struct_span_err, DiagnosticBuilder, FatalError}; +use rustc_errors::{struct_span_err, FatalError}; use rustc_session::config::{self, CrateType}; use rustc_session::cstore::{CrateSource, MetadataLoader}; use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch}; @@ -931,8 +931,8 @@ impl fmt::Display for MetadataError<'_> { } impl CrateError { - fn build_diag(self, sess: &Session, span: Span, missing_core: bool) -> DiagnosticBuilder<'_> { - match self { + crate fn report(self, sess: &Session, span: Span, missing_core: bool) { + let mut diag = match self { CrateError::NonAsciiName(crate_name) => sess.struct_span_err( span, &format!("cannot load a crate with a non-ascii name `{}`", crate_name), @@ -1208,10 +1208,8 @@ impl CrateError { "plugin `{}` only found in rlib format, but must be available in dylib format", crate_name, ), - } - } + }; - crate fn report(self, sess: &Session, span: Span, missing_core: bool) { - self.build_diag(sess, span, missing_core).emit(); + diag.emit(); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index aaa946f75421b..c936e08d536a4 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -840,57 +840,41 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let parent_scope = self.parent_scope; let expansion = parent_scope.expansion; - let module = if orig_name.is_none() && ident.name == kw::SelfLower { + let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower { self.r .session .struct_span_err(item.span, "`extern crate self;` requires renaming") .span_suggestion( item.span, - "try", + "rename the `self` crate to be able to import it", "extern crate self as name;".into(), Applicability::HasPlaceholders, ) .emit(); return; } else if orig_name == Some(kw::SelfLower) { - self.r.graph_root + Some(self.r.graph_root) } else { - match self.r.crate_loader.process_extern_crate(item, &self.r.definitions, local_def_id) - { - Some(crate_id) => { + self.r.crate_loader.process_extern_crate(item, &self.r.definitions, local_def_id).map( + |crate_id| { self.r.extern_crate_map.insert(local_def_id, crate_id); self.r.expect_module(crate_id.as_def_id()) - } - _ => { - let dummy_import = self.r.arenas.alloc_import(Import { - kind: ImportKind::ExternCrate { source: orig_name, target: ident }, - root_id: item.id, - id: item.id, - parent_scope: self.parent_scope, - imported_module: Cell::new(None), - has_attributes: !item.attrs.is_empty(), - use_span_with_attributes: item.span_with_attributes(), - use_span: item.span, - root_span: item.span, - span: item.span, - module_path: Vec::new(), - vis: Cell::new(vis), - used: Cell::new(true), - }); - self.r.import_dummy_binding(dummy_import); - return; - } - } - }; - let used = self.process_macro_use_imports(item, module); - let binding = - (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); + }, + ) + } + .map(|module| { + let used = self.process_macro_use_imports(item, module); + let binding = + (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); + (used, Some(ModuleOrUniformRoot::Module(module)), binding) + }) + .unwrap_or((true, None, self.r.dummy_binding)); let import = self.r.arenas.alloc_import(Import { kind: ImportKind::ExternCrate { source: orig_name, target: ident }, root_id: item.id, id: item.id, parent_scope: self.parent_scope, - imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), + imported_module: Cell::new(module), has_attributes: !item.attrs.is_empty(), use_span_with_attributes: item.span_with_attributes(), use_span: item.span, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d2c64b7e4418d..bf4cece8bde8d 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -600,10 +600,8 @@ impl<'a> Resolver<'a> { // Define a "dummy" resolution containing a Res::Err as a placeholder for a // failed resolution - crate fn import_dummy_binding(&mut self, import: &'a Import<'a>) { - if let ImportKind::Single { target, .. } | ImportKind::ExternCrate { target, .. } = - import.kind - { + fn import_dummy_binding(&mut self, import: &'a Import<'a>) { + if let ImportKind::Single { target, .. } = import.kind { let dummy_binding = self.dummy_binding; let dummy_binding = self.import(dummy_binding, import); self.per_ns(|this, ns| { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d17e8875a1ec0..1c084086ceb02 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -3288,7 +3288,9 @@ impl<'a> Resolver<'a> { Some(binding) } else { let crate_id = if !speculative { - self.crate_loader.process_path_extern(ident.name, ident.span) + let Some(crate_id) = + self.crate_loader.process_path_extern(ident.name, ident.span) else { return Some(self.dummy_binding); }; + crate_id } else { self.crate_loader.maybe_process_path_extern(ident.name)? }; diff --git a/src/test/ui/crate-loading/invalid-rlib.rs b/src/test/ui/crate-loading/invalid-rlib.rs index 77c29090a3ee0..aea861e3261b5 100644 --- a/src/test/ui/crate-loading/invalid-rlib.rs +++ b/src/test/ui/crate-loading/invalid-rlib.rs @@ -6,3 +6,5 @@ #![no_std] use ::foo; //~ ERROR invalid metadata files for crate `foo` //~| NOTE failed to mmap file +//~^^ ERROR invalid metadata files for crate `foo` +//~| NOTE failed to mmap file diff --git a/src/test/ui/crate-loading/invalid-rlib.stderr b/src/test/ui/crate-loading/invalid-rlib.stderr index b2c79f742fb30..3c0d23bf7b4cc 100644 --- a/src/test/ui/crate-loading/invalid-rlib.stderr +++ b/src/test/ui/crate-loading/invalid-rlib.stderr @@ -6,6 +6,14 @@ LL | use ::foo; | = note: failed to mmap file 'auxiliary/libfoo.rlib' -error: aborting due to previous error +error[E0786]: found invalid metadata files for crate `foo` + --> $DIR/invalid-rlib.rs:7:7 + | +LL | use ::foo; + | ^^^ + | + = note: failed to mmap file 'auxiliary/libfoo.rlib' + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0786`. diff --git a/src/test/ui/extern/extern-crate-multiple-missing.rs b/src/test/ui/extern/extern-crate-multiple-missing.rs index fa7da83a6dfef..a6560ca78624d 100644 --- a/src/test/ui/extern/extern-crate-multiple-missing.rs +++ b/src/test/ui/extern/extern-crate-multiple-missing.rs @@ -3,6 +3,8 @@ extern crate bar; //~ ERROR can't find crate for `bar` extern crate foo; //~ ERROR can't find crate for `foo` fn main() { + // If the crate name introduced by `extern crate` failed to resolve then subsequent + // derived paths do not emit additional errors foo::something(); bar::something(); } diff --git a/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr b/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr index 8f369f1b03831..127765727b401 100644 --- a/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr +++ b/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr @@ -2,7 +2,12 @@ error: `extern crate self;` requires renaming --> $DIR/extern-crate-self-fail.rs:1:1 | LL | extern crate self; - | ^^^^^^^^^^^^^^^^^^ help: try: `extern crate self as name;` + | ^^^^^^^^^^^^^^^^^^ + | +help: rename the `self` crate to be able to import it + | +LL | extern crate self as name; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: `#[macro_use]` is not supported on `extern crate self` --> $DIR/extern-crate-self-fail.rs:3:1 diff --git a/src/test/ui/rust-2018/uniform-paths/deadlock.rs b/src/test/ui/rust-2018/uniform-paths/deadlock.rs index 83ed70a0459a8..2427bde6d18bc 100644 --- a/src/test/ui/rust-2018/uniform-paths/deadlock.rs +++ b/src/test/ui/rust-2018/uniform-paths/deadlock.rs @@ -1,7 +1,8 @@ // edition:2018 // compile-flags:--extern foo --extern bar +use bar::foo; //~ ERROR can't find crate for `bar` use foo::bar; //~ ERROR can't find crate for `foo` -use bar::foo; +//~^^ ERROR unresolved imports `bar::foo`, `foo::bar` fn main() {} diff --git a/src/test/ui/rust-2018/uniform-paths/deadlock.stderr b/src/test/ui/rust-2018/uniform-paths/deadlock.stderr index 9336e90afb71d..8b9863948bd6c 100644 --- a/src/test/ui/rust-2018/uniform-paths/deadlock.stderr +++ b/src/test/ui/rust-2018/uniform-paths/deadlock.stderr @@ -1,9 +1,24 @@ -error[E0463]: can't find crate for `foo` +error[E0463]: can't find crate for `bar` --> $DIR/deadlock.rs:4:5 | +LL | use bar::foo; + | ^^^ can't find crate + +error[E0463]: can't find crate for `foo` + --> $DIR/deadlock.rs:5:5 + | LL | use foo::bar; | ^^^ can't find crate -error: aborting due to previous error +error[E0432]: unresolved imports `bar::foo`, `foo::bar` + --> $DIR/deadlock.rs:4:5 + | +LL | use bar::foo; + | ^^^^^^^^ +LL | use foo::bar; + | ^^^^^^^^ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0463`. +Some errors have detailed explanations: E0432, E0463. +For more information about an error, try `rustc --explain E0432`. From 692e96c327321eba464d4ee57f55d448d031b607 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 29 Nov 2021 15:24:44 -0500 Subject: [PATCH 17/18] Bless nll --- ...mplied-bounds-unnorm-associated-type.nll.stderr | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr new file mode 100644 index 0000000000000..e37ec7f26651c --- /dev/null +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5 + | +LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | s + | ^ returning this value requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to previous error + From 188d670125bda9cc2cf7d032aeb20d8c71070be6 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 29 Nov 2021 12:58:15 -0800 Subject: [PATCH 18/18] Don't re-export `MirPass` --- compiler/rustc_const_eval/src/transform/mod.rs | 2 -- compiler/rustc_const_eval/src/transform/promote_consts.rs | 1 - compiler/rustc_const_eval/src/transform/validate.rs | 5 ++--- compiler/rustc_mir_transform/src/lib.rs | 3 +-- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/mod.rs b/compiler/rustc_const_eval/src/transform/mod.rs index 38c28f34934a4..a2928bdf51b83 100644 --- a/compiler/rustc_const_eval/src/transform/mod.rs +++ b/compiler/rustc_const_eval/src/transform/mod.rs @@ -1,5 +1,3 @@ pub mod check_consts; pub mod promote_consts; pub mod validate; - -pub use rustc_middle::mir::MirPass; diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index a92b20f5cb520..464155db89f48 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -27,7 +27,6 @@ use std::cell::Cell; use std::{cmp, iter, mem}; use crate::transform::check_consts::{qualifs, ConstCx}; -use crate::transform::MirPass; /// A `MirPass` for promotion. /// diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 0ab077cf2bf40..c86c8f81dbd96 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1,14 +1,13 @@ //! Validates the MIR to ensure that invariants are upheld. -use super::MirPass; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::traversal; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ - AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem, - PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator, + AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPass, MirPhase, Operand, + PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, START_BLOCK, }; use rustc_middle::ty::fold::BottomUpFolder; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index f9ef314627807..b0bea7312a7eb 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -27,7 +27,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::Visitor as _; -use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPhase, Promoted}; +use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_span::{Span, Symbol}; @@ -78,7 +78,6 @@ mod unreachable_prop; use rustc_const_eval::transform::check_consts; use rustc_const_eval::transform::promote_consts; use rustc_const_eval::transform::validate; -pub use rustc_const_eval::transform::MirPass; use rustc_mir_dataflow::rustc_peek; pub fn provide(providers: &mut Providers) {