diff options
| author | bors <bors@rust-lang.org> | 2021-06-22 07:01:54 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-06-22 07:01:54 +0000 |
| commit | 44f4a87d7047db0deff5ef033fd2af820722e9a5 (patch) | |
| tree | 4960627de594af7fc920104a8f40245e480485e9 | |
| parent | c38111c4fb9c22a36f9a9195d1884052bb670af2 (diff) | |
| parent | aa3580baa6f5ef69aba41a63297fb659bcd4b793 (diff) | |
| download | rust-44f4a87d7047db0deff5ef033fd2af820722e9a5.tar.gz rust-44f4a87d7047db0deff5ef033fd2af820722e9a5.zip | |
Auto merge of #85707 - jam1garner:future_prelude_collision_lint, r=nikomatsakis
Add `future_prelude_collision` lint Implements #84594. (RFC rust-lang/rfcs#3114 ([rendered](https://github.com/rust-lang/rfcs/blob/master/text/3114-prelude-2021.md))) Not entirely complete but wanted to have my progress decently available while I finish off the last little bits. Things left to implement: * [x] UI tests for lints * [x] Only emit lint for 2015 and 2018 editions * [ ] Lint name/message bikeshedding * [x] Implement for `FromIterator` (from best I can tell, the current approach as mentioned from [this comment](https://github.com/rust-lang/rust/issues/84594#issuecomment-847288288) won't work due to `FromIterator` instances not using dot-call syntax, but if I'm correct about this then that would also need to be fixed for `TryFrom`/`TryInto`)* * [x] Add to `rust-2021-migration` group? (See #85512) (added to `rust-2021-compatibility` group) * [ ] Link to edition guide in lint docs *edit: looked into it, `lookup_method` will also not be hit for `TryFrom`/`TryInto` for non-dotcall syntax. If anyone who is more familiar with typecheck knows the equivalent for looking up associated functions, feel free to chime in.
22 files changed, 1144 insertions, 31 deletions
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f95d4a6ca54..a2f60142ffc 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3001,6 +3001,7 @@ declare_lint_pass! { PROC_MACRO_BACK_COMPAT, OR_PATTERNS_BACK_COMPAT, LARGE_ASSIGNMENTS, + FUTURE_PRELUDE_COLLISION, ] } @@ -3244,3 +3245,52 @@ declare_lint! { edition: Some(Edition::Edition2021), }; } + +declare_lint! { + /// The `future_prelude_collision` lint detects the usage of trait methods which are ambiguous + /// with traits added to the prelude in future editions. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(future_prelude_collision)] + /// + /// trait Foo { + /// fn try_into(self) -> Result<String, !>; + /// } + /// + /// impl Foo for &str { + /// fn try_into(self) -> Result<String, !> { + /// Ok(String::from(self)) + /// } + /// } + /// + /// fn main() { + /// let x: String = "3".try_into().unwrap(); + /// // ^^^^^^^^ + /// // This call to try_into matches both Foo:try_into and TryInto::try_into as + /// // `TryInto` has been added to the Rust prelude in 2021 edition. + /// println!("{}", x); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In Rust 2021, one of the important introductions is the [prelude changes], which add + /// `TryFrom`, `TryInto`, and `FromIterator` into the standard library's prelude. Since this + /// results in an amiguity as to which method/function to call when an existing `try_into` + /// method is called via dot-call syntax or a `try_from`/`from_iter` associated function + /// is called directly on a type. + /// + /// [prelude changes]: https://blog.rust-lang.org/inside-rust/2021/03/04/planning-rust-2021.html#prelude-changes + pub FUTURE_PRELUDE_COLLISION, + Allow, + "detects the usage of trait methods which are ambiguous with traits added to the \ + prelude in future editions", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #85684 <https://github.com/rust-lang/rust/issues/85684>", + edition: Some(Edition::Edition2021), + }; +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b81d29930ee..55b6056209d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -586,6 +586,7 @@ symbols! { from, from_desugaring, from_generator, + from_iter, from_method, from_output, from_residual, @@ -1238,7 +1239,9 @@ symbols! { truncf32, truncf64, try_blocks, + try_from, try_from_trait, + try_into, try_into_trait, try_trait_v2, tt, diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index d0cbb58fb10..28ab6b15133 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -466,7 +466,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span); + let (res, opt_ty, segs) = + self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span); let ty = match res { Res::Err => { self.set_tainted_by_errors(); @@ -940,7 +941,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // no need to check for bot/err -- callee does that let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t); - let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) { + let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) { Ok(method) => { // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to // trigger this codepath causing `structuraly_resolved_type` to emit an error. diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 96569ae0e77..8e33f4f9e12 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -906,13 +906,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Resolves an associated value path into a base type and associated constant, or method /// resolution. The newly resolved definition is written into `type_dependent_defs`. - pub fn resolve_ty_and_res_ufcs( + pub fn resolve_ty_and_res_fully_qualified_call( &self, qpath: &'tcx QPath<'tcx>, hir_id: hir::HirId, span: Span, ) -> (Res, Option<Ty<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) { - debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span); + debug!( + "resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}", + qpath, hir_id, span + ); let (ty, qself, item_segment) = match *qpath { QPath::Resolved(ref opt_qself, ref path) => { return ( @@ -922,7 +925,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), - QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"), + QPath::LangItem(..) => { + bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`") + } }; if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) { @@ -932,25 +937,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return (def, Some(ty), slice::from_ref(&**item_segment)); } let item_name = item_segment.ident; - let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| { - let result = match error { - method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), - _ => Err(ErrorReported), - }; - if item_name.name != kw::Empty { - if let Some(mut e) = self.report_method_error( - span, - ty, - item_name, - SelfSource::QPath(qself), - error, - None, - ) { - e.emit(); + let result = self + .resolve_fully_qualified_call(span, item_name, ty, qself.span, hir_id) + .or_else(|error| { + let result = match error { + method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), + _ => Err(ErrorReported), + }; + if item_name.name != kw::Empty { + if let Some(mut e) = self.report_method_error( + span, + ty, + item_name, + SelfSource::QPath(qself), + error, + None, + ) { + e.emit(); + } } - } - result - }); + result + }); if result.is_ok() { self.maybe_lint_bare_trait(qpath, hir_id); diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 427102afee1..be6bc625d89 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -3,6 +3,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html mod confirm; +mod prelude2021; pub mod probe; mod suggest; @@ -173,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// # Arguments /// - /// Given a method call like `foo.bar::<T1,...Tn>(...)`: + /// Given a method call like `foo.bar::<T1,...Tn>(a, b + 1, ...)`: /// /// * `self`: the surrounding `FnCtxt` (!) /// * `self_ty`: the (unadjusted) type of the self expression (`foo`) @@ -181,6 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// * `span`: the span for the method call /// * `call_expr`: the complete method call: (`foo.bar::<T1,...Tn>(...)`) /// * `self_expr`: the self expression (`foo`) + /// * `args`: the expressions of the arguments (`a, b + 1, ...`) #[instrument(level = "debug", skip(self, call_expr, self_expr))] pub fn lookup_method( &self, @@ -189,6 +191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, call_expr: &'tcx hir::Expr<'tcx>, self_expr: &'tcx hir::Expr<'tcx>, + args: &'tcx [hir::Expr<'tcx>], ) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> { debug!( "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", @@ -198,6 +201,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pick = self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; + self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args); + for import_id in &pick.import_ids { debug!("used_trait_import: {:?}", import_id); Lrc::get_mut(&mut self.typeck_results.borrow_mut().used_trait_imports) @@ -417,16 +422,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(InferOk { obligations, value: callee }) } + /// Performs a [full-qualified function call] (formerly "universal function call") lookup. If + /// lookup is successful, it will return the type of definition and the [`DefId`] of the found + /// function definition. + /// + /// [full-qualified function call]: https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls + /// + /// # Arguments + /// + /// Given a function call like `Foo::bar::<T1,...Tn>(...)`: + /// + /// * `self`: the surrounding `FnCtxt` (!) + /// * `span`: the span of the call, excluding arguments (`Foo::bar::<T1, ...Tn>`) + /// * `method_name`: the identifier of the function within the container type (`bar`) + /// * `self_ty`: the type to search within (`Foo`) + /// * `self_ty_span` the span for the type being searched within (span of `Foo`) + /// * `expr_id`: the [`hir::HirId`] of the expression composing the entire call #[instrument(level = "debug", skip(self))] - pub fn resolve_ufcs( + pub fn resolve_fully_qualified_call( &self, span: Span, method_name: Ident, self_ty: Ty<'tcx>, + self_ty_span: Span, expr_id: hir::HirId, ) -> Result<(DefKind, DefId), MethodError<'tcx>> { debug!( - "resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}", + "resolve_fully_qualified_call: method_name={:?} self_ty={:?} expr_id={:?}", method_name, self_ty, expr_id, ); @@ -463,18 +485,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_id, ProbeScope::TraitsInScope, )?; - debug!("resolve_ufcs: pick={:?}", pick); + + self.lint_fully_qualified_call_from_2018( + span, + method_name, + self_ty, + self_ty_span, + expr_id, + &pick, + ); + + debug!("resolve_fully_qualified_call: pick={:?}", pick); { let mut typeck_results = self.typeck_results.borrow_mut(); let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap(); for import_id in pick.import_ids { - debug!("resolve_ufcs: used_trait_import: {:?}", import_id); + debug!("resolve_fully_qualified_call: used_trait_import: {:?}", import_id); used_trait_imports.insert(import_id); } } let def_kind = pick.item.kind.as_def_kind(); - debug!("resolve_ufcs: def_kind={:?}, def_id={:?}", def_kind, pick.item.def_id); + debug!( + "resolve_fully_qualified_call: def_kind={:?}, def_id={:?}", + def_kind, pick.item.def_id + ); tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span)); Ok((def_kind, pick.item.def_id)) } diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs new file mode 100644 index 00000000000..4c925a6f237 --- /dev/null +++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs @@ -0,0 +1,330 @@ +use hir::def_id::DefId; +use hir::HirId; +use hir::ItemKind; +use rustc_ast::Mutability; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_middle::ty::{Ref, Ty}; +use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION; +use rustc_span::symbol::kw::Underscore; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::Span; + +use crate::check::{ + method::probe::{self, Pick}, + FnCtxt, +}; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub(super) fn lint_dot_call_from_2018( + &self, + self_ty: Ty<'tcx>, + segment: &hir::PathSegment<'_>, + span: Span, + call_expr: &'tcx hir::Expr<'tcx>, + self_expr: &'tcx hir::Expr<'tcx>, + pick: &Pick<'tcx>, + args: &'tcx [hir::Expr<'tcx>], + ) { + debug!( + "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", + segment.ident, self_ty, call_expr, self_expr + ); + + // Rust 2021 and later is already using the new prelude + if span.rust_2021() { + return; + } + + // These are the method names that were added to prelude in Rust 2021 + if !matches!(segment.ident.name, sym::try_into) { + return; + } + + // No need to lint if method came from std/core, as that will now be in the prelude + if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) { + return; + } + + if matches!(pick.kind, probe::PickKind::InherentImplPick | probe::PickKind::ObjectPick) { + // avoid repeatedly adding unneeded `&*`s + if pick.autoderefs == 1 + && matches!( + pick.autoref_or_ptr_adjustment, + Some(probe::AutorefOrPtrAdjustment::Autoref { .. }) + ) + && matches!(self_ty.kind(), Ref(..)) + { + return; + } + // Inherent impls only require not relying on autoref and autoderef in order to + // ensure that the trait implementation won't be used + self.tcx.struct_span_lint_hir( + FUTURE_PRELUDE_COLLISION, + self_expr.hir_id, + self_expr.span, + |lint| { + let sp = self_expr.span; + + let mut lint = lint.build(&format!( + "trait method `{}` will become ambiguous in Rust 2021", + segment.ident.name + )); + + let derefs = "*".repeat(pick.autoderefs); + + let autoref = match pick.autoref_or_ptr_adjustment { + Some(probe::AutorefOrPtrAdjustment::Autoref { + mutbl: Mutability::Mut, + .. + }) => "&mut ", + Some(probe::AutorefOrPtrAdjustment::Autoref { + mutbl: Mutability::Not, + .. + }) => "&", + Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", + }; + if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) + { + let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + pick.autoref_or_ptr_adjustment + { + format!("{}{} as *const _", derefs, self_expr) + } else { + format!("{}{}{}", autoref, derefs, self_expr) + }; + + lint.span_suggestion( + sp, + "disambiguate the method call", + format!("({})", self_adjusted), + Applicability::MachineApplicable, + ); + } else { + let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + pick.autoref_or_ptr_adjustment + { + format!("{}(...) as *const _", derefs) + } else { + format!("{}{}...", autoref, derefs) + }; + lint.span_help( + sp, + &format!("disambiguate the method call with `({})`", self_adjusted,), + ); + } + + lint.emit(); + }, + ); + } else { + // trait implementations require full disambiguation to not clash with the new prelude + // additions (i.e. convert from dot-call to fully-qualified call) + self.tcx.struct_span_lint_hir( + FUTURE_PRELUDE_COLLISION, + call_expr.hir_id, + call_expr.span, + |lint| { + let sp = call_expr.span; + let trait_name = self.trait_path_or_bare_name( + span, + call_expr.hir_id, + pick.item.container.id(), + ); + + let mut lint = lint.build(&format!( + "trait method `{}` will become ambiguous in Rust 2021", + segment.ident.name + )); + + let (self_adjusted, precise) = self.adjust_expr(pick, self_expr); + if precise { + let args = args + .iter() + .skip(1) + .map(|arg| { + format!( + ", {}", + self.sess().source_map().span_to_snippet(arg.span).unwrap() + ) + }) + .collect::<String>(); + + lint.span_suggestion( + sp, + "disambiguate the associated function", + format!( + "{}::{}({}{})", + trait_name, segment.ident.name, self_adjusted, args + ), + Applicability::MachineApplicable, + ); + } else { + lint.span_help( + sp, + &format!( + "disambiguate the associated function with `{}::{}(...)`", + trait_name, segment.ident, + ), + ); + } + + lint.emit(); + }, + ); + } + } + + pub(super) fn lint_fully_qualified_call_from_2018( + &self, + span: Span, + method_name: Ident, + self_ty: Ty<'tcx>, + self_ty_span: Span, + expr_id: hir::HirId, + pick: &Pick<'tcx>, + ) { + // Rust 2021 and later is already using the new prelude + if span.rust_2021() { + return; + } + + // These are the fully qualified methods added to prelude in Rust 2021 + if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) { + return; + } + + // No need to lint if method came from std/core, as that will now be in the prelude + if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) { + return; + } + + // No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`, + // since such methods take precedence over trait methods. + if matches!(pick.kind, probe::PickKind::InherentImplPick) { + return; + } + + self.tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| { + // "type" refers to either a type or, more likely, a trait from which + // the associated function or method is from. + let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id()); + let trait_generics = self.tcx.generics_of(pick.item.container.id()); + + let parameter_count = trait_generics.count() - (trait_generics.has_self as usize); + let trait_name = if parameter_count == 0 { + trait_path + } else { + format!( + "{}<{}>", + trait_path, + std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ") + ) + }; + + let mut lint = lint.build(&format!( + "trait-associated function `{}` will become ambiguous in Rust 2021", + method_name.name + )); + + let self_ty = self + .sess() + .source_map() + .span_to_snippet(self_ty_span) + .unwrap_or_else(|_| self_ty.to_string()); + + lint.span_suggestion( + span, + "disambiguate the associated function", + format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,), + Applicability::MachineApplicable, + ); + + lint.emit(); + }); + } + + fn trait_path_or_bare_name( + &self, + span: Span, + expr_hir_id: HirId, + trait_def_id: DefId, + ) -> String { + self.trait_path(span, expr_hir_id, trait_def_id).unwrap_or_else(|| { + let key = self.tcx.def_key(trait_def_id); + format!("{}", key.disambiguated_data.data) + }) + } + + fn trait_path(&self, span: Span, expr_hir_id: HirId, trait_def_id: DefId) -> Option<String> { + let applicable_traits = self.tcx.in_scope_traits(expr_hir_id)?; + let applicable_trait = applicable_traits.iter().find(|t| t.def_id == trait_def_id)?; + if applicable_trait.import_ids.is_empty() { + // The trait was declared within the module, we only need to use its name. + return None; + } + + let import_items: Vec<_> = applicable_trait + .import_ids + .iter() + .map(|&import_id| { + let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id); + self.tcx.hir().expect_item(hir_id) + }) + .collect(); + + // Find an identifier with which this trait was imported (note that `_` doesn't count). + let any_id = import_items + .iter() + .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None }) + .next(); + if let Some(any_id) = any_id { + return Some(format!("{}", any_id)); + } + + // All that is left is `_`! We need to use the full path. It doesn't matter which one we pick, + // so just take the first one. + match import_items[0].kind { + ItemKind::Use(path, _) => Some( + path.segments + .iter() + .map(|segment| segment.ident.to_string()) + .collect::<Vec<_>>() + .join("::"), + ), + _ => { + span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind); + } + } + } + + /// Creates a string version of the `expr` that includes explicit adjustments. + /// Returns the string and also a bool indicating whther this is a *precise* + /// suggestion. + fn adjust_expr(&self, pick: &Pick<'tcx>, expr: &hir::Expr<'tcx>) -> (String, bool) { + let derefs = "*".repeat(pick.autoderefs); + + let autoref = match pick.autoref_or_ptr_adjustment { + Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Mut, .. }) => "&mut ", + Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Not, .. }) => "&", + Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", + }; + + let (expr_text, precise) = + if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { + (expr_text, true) + } else { + (format!("(..)"), false) + }; + + let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + pick.autoref_or_ptr_adjustment + { + format!("{}{} as *const _", derefs, expr_text) + } else { + format!("{}{}{}", autoref, derefs, expr_text) + }; + + (adjusted_text, precise) + } +} diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 3ac760e2363..2879614d0c8 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -160,7 +160,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ti: TopInfo<'tcx>, ) { let path_res = match &pat.kind { - PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)), + PatKind::Path(qpath) => { + Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span)) + } _ => None, }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); @@ -904,7 +906,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Resolve the path and check the definition for errors. - let (res, opt_ty, segments) = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span); + let (res, opt_ty, segments) = + self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span); if res == Res::Err { self.set_tainted_by_errors(); on_error(); diff --git a/src/test/ui/rust-2021/future-prelude-collision-imported.fixed b/src/test/ui/rust-2021/future-prelude-collision-imported.fixed new file mode 100644 index 00000000000..4f8fd9b345b --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-imported.fixed @@ -0,0 +1,59 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(future_prelude_collision)] +#![allow(dead_code)] +#![allow(unused_imports)] + +mod m { + pub trait TryIntoU32 { + fn try_into(self) -> Result<u32, ()>; + } + + impl TryIntoU32 for u8 { + fn try_into(self) -> Result<u32, ()> { + Ok(self as u32) + } + } + + pub trait AnotherTrick {} +} + +mod a { + use crate::m::TryIntoU32; + + fn main() { + // In this case, we can just use `TryIntoU32` + let _: u32 = TryIntoU32::try_into(3u8).unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + } +} + +mod b { + use crate::m::AnotherTrick as TryIntoU32; + use crate::m::TryIntoU32 as _; + + fn main() { + // In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use + // the path `crate::m::TryIntoU32` (with which it was imported). + let _: u32 = crate::m::TryIntoU32::try_into(3u8).unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + } +} + +mod c { + use super::m::TryIntoU32 as _; + use crate::m::AnotherTrick as TryIntoU32; + + fn main() { + // In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use + // the path `super::m::TryIntoU32` (with which it was imported). + let _: u32 = super::m::TryIntoU32::try_into(3u8).unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + } +} + +fn main() {} diff --git a/src/test/ui/rust-2021/future-prelude-collision-imported.rs b/src/test/ui/rust-2021/future-prelude-collision-imported.rs new file mode 100644 index 00000000000..2ce1be6151b --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-imported.rs @@ -0,0 +1,59 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(future_prelude_collision)] +#![allow(dead_code)] +#![allow(unused_imports)] + +mod m { + pub trait TryIntoU32 { + fn try_into(self) -> Result<u32, ()>; + } + + impl TryIntoU32 for u8 { + fn try_into(self) -> Result<u32, ()> { + Ok(self as u32) + } + } + + pub trait AnotherTrick {} +} + +mod a { + use crate::m::TryIntoU32; + + fn main() { + // In this case, we can just use `TryIntoU32` + let _: u32 = 3u8.try_into().unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + } +} + +mod b { + use crate::m::AnotherTrick as TryIntoU32; + use crate::m::TryIntoU32 as _; + + fn main() { + // In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use + // the path `crate::m::TryIntoU32` (with which it was imported). + let _: u32 = 3u8.try_into().unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + } +} + +mod c { + use super::m::TryIntoU32 as _; + use crate::m::AnotherTrick as TryIntoU32; + + fn main() { + // In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use + // the path `super::m::TryIntoU32` (with which it was imported). + let _: u32 = 3u8.try_into().unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + } +} + +fn main() {} diff --git a/src/test/ui/rust-2021/future-prelude-collision-imported.stderr b/src/test/ui/rust-2021/future-prelude-collision-imported.stderr new file mode 100644 index 00000000000..3903cbfe824 --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-imported.stderr @@ -0,0 +1,34 @@ +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-imported.rs:27:22 + | +LL | let _: u32 = 3u8.try_into().unwrap(); + | ^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(3u8)` + | +note: the lint level is defined here + --> $DIR/future-prelude-collision-imported.rs:4:9 + | +LL | #![warn(future_prelude_collision)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-imported.rs:40:22 + | +LL | let _: u32 = 3u8.try_into().unwrap(); + | ^^^^^^^^^^^^^^ help: disambiguate the associated function: `crate::m::TryIntoU32::try_into(3u8)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-imported.rs:53:22 + | +LL | let _: u32 = 3u8.try_into().unwrap(); + | ^^^^^^^^^^^^^^ help: disambiguate the associated function: `super::m::TryIntoU32::try_into(3u8)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: 3 warnings emitted + diff --git a/src/test/ui/rust-2021/future-prelude-collision-shadow.rs b/src/test/ui/rust-2021/future-prelude-collision-shadow.rs new file mode 100644 index 00000000000..c9d2529341f --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-shadow.rs @@ -0,0 +1,32 @@ +// edition:2018 +#![warn(future_prelude_collision)] +#![allow(dead_code)] +#![allow(unused_imports)] + +mod m { + pub trait TryIntoU32 { + fn try_into(self) -> Result<u32, ()>; + } + + impl TryIntoU32 for u8 { + fn try_into(self) -> Result<u32, ()> { + Ok(self as u32) + } + } + + pub trait AnotherTrick {} +} + +mod d { + use crate::m::AnotherTrick as TryIntoU32; + use crate::m::*; + + fn main() { + // Here, `TryIntoU32` is imported but shadowed, but in that case we don't permit its methods + // to be available. + let _: u32 = 3u8.try_into().unwrap(); + //~^ ERROR no method named `try_into` found for type `u8` in the current scope + } +} + +fn main() {} diff --git a/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr b/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr new file mode 100644 index 00000000000..ad9b8af00e4 --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-shadow.stderr @@ -0,0 +1,40 @@ +error[E0599]: no method named `try_into` found for type `u8` in the current scope + --> $DIR/future-prelude-collision-shadow.rs:27:26 + | +LL | let _: u32 = 3u8.try_into().unwrap(); + | ^^^^^^^^ method not found in `u8` + | + ::: $SRC_DIR/core/src/convert/mod.rs:LL:COL + | +LL | fn try_into(self) -> Result<T, Self::Error>; + | -------- + | | + | the method is available for `Box<u8>` here + | the method is available for `Pin<u8>` here + | the method is available for `Arc<u8>` here + | the method is available for `Rc<u8>` here + | + = help: items from traits can only be used if the trait is in scope + = note: the following traits are implemented but not in scope; perhaps add a `use` for one of them: + candidate #1: `use crate::m::TryIntoU32;` + candidate #2: `use std::convert::TryInto;` +help: consider wrapping the receiver expression with the appropriate type + | +LL | let _: u32 = Box::new(3u8).try_into().unwrap(); + | ^^^^^^^^^ ^ +help: consider wrapping the receiver expression with the appropriate type + | +LL | let _: u32 = Pin::new(3u8).try_into().unwrap(); + | ^^^^^^^^^ ^ +help: consider wrapping the receiver expression with the appropriate type + | +LL | let _: u32 = Arc::new(3u8).try_into().unwrap(); + | ^^^^^^^^^ ^ +help: consider wrapping the receiver expression with the appropriate type + | +LL | let _: u32 = Rc::new(3u8).try_into().unwrap(); + | ^^^^^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/rust-2021/future-prelude-collision.fixed b/src/test/ui/rust-2021/future-prelude-collision.fixed new file mode 100644 index 00000000000..9ede9f3a2fb --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision.fixed @@ -0,0 +1,96 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(future_prelude_collision)] + +trait TryIntoU32 { + fn try_into(self) -> Result<u32, ()>; +} + +impl TryIntoU32 for u8 { + fn try_into(self) -> Result<u32, ()> { + Ok(self as u32) + } +} + +// needed for autoref test +impl TryIntoU32 for &f32 { + fn try_into(self) -> Result<u32, ()> { + Ok(*self as u32) + } +} + +trait TryFromU8: Sized { + fn try_from(x: u8) -> Result<Self, ()>; +} + +impl TryFromU8 for u32 { + fn try_from(x: u8) -> Result<Self, ()> { + Ok(x as u32) + } +} + +impl TryIntoU32 for *const u16 { + fn try_into(self) -> Result<u32, ()> { + Ok(unsafe { *self } as u32) + } +} + +trait FromByteIterator { + fn from_iter<T>(iter: T) -> Self + where T: Iterator<Item = u8>; +} + +impl FromByteIterator for Vec<u8> { + fn from_iter<T>(iter: T) -> Self + where T: Iterator<Item = u8> + { + iter.collect() + } +} + +fn main() { + // test dot-call that will break in 2021 edition + let _: u32 = TryIntoU32::try_into(3u8).unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + // test associated function call that will break in 2021 edition + let _ = <u32 as TryFromU8>::try_from(3u8).unwrap(); + //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + // test reverse turbofish too + let _ = <Vec<u8> as FromByteIterator>::from_iter(vec![1u8, 2, 3, 4, 5, 6].into_iter()); + //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + // negative testing lint (this line should *not* emit a warning) + let _: u32 = TryFromU8::try_from(3u8).unwrap(); + + // test type omission + let _: u32 = <_ as TryFromU8>::try_from(3u8).unwrap(); + //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + // test autoderef + let _: u32 = TryIntoU32::try_into(*(&3u8)).unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + // test autoref + let _: u32 = TryIntoU32::try_into(&3.0).unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + let mut data = 3u16; + let mut_ptr = std::ptr::addr_of_mut!(data); + let _: u32 = TryIntoU32::try_into(mut_ptr as *const _).unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + type U32Alias = u32; + let _ = <U32Alias as TryFromU8>::try_from(3u8).unwrap(); + //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! +} diff --git a/src/test/ui/rust-2021/future-prelude-collision.rs b/src/test/ui/rust-2021/future-prelude-collision.rs new file mode 100644 index 00000000000..914e910396a --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision.rs @@ -0,0 +1,96 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(future_prelude_collision)] + +trait TryIntoU32 { + fn try_into(self) -> Result<u32, ()>; +} + +impl TryIntoU32 for u8 { + fn try_into(self) -> Result<u32, ()> { + Ok(self as u32) + } +} + +// needed for autoref test +impl TryIntoU32 for &f32 { + fn try_into(self) -> Result<u32, ()> { + Ok(*self as u32) + } +} + +trait TryFromU8: Sized { + fn try_from(x: u8) -> Result<Self, ()>; +} + +impl TryFromU8 for u32 { + fn try_from(x: u8) -> Result<Self, ()> { + Ok(x as u32) + } +} + +impl TryIntoU32 for *const u16 { + fn try_into(self) -> Result<u32, ()> { + Ok(unsafe { *self } as u32) + } +} + +trait FromByteIterator { + fn from_iter<T>(iter: T) -> Self + where T: Iterator<Item = u8>; +} + +impl FromByteIterator for Vec<u8> { + fn from_iter<T>(iter: T) -> Self + where T: Iterator<Item = u8> + { + iter.collect() + } +} + +fn main() { + // test dot-call that will break in 2021 edition + let _: u32 = 3u8.try_into().unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + // test associated function call that will break in 2021 edition + let _ = u32::try_from(3u8).unwrap(); + //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + // test reverse turbofish too + let _ = <Vec<u8>>::from_iter(vec![1u8, 2, 3, 4, 5, 6].into_iter()); + //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + // negative testing lint (this line should *not* emit a warning) + let _: u32 = TryFromU8::try_from(3u8).unwrap(); + + // test type omission + let _: u32 = <_>::try_from(3u8).unwrap(); + //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + // test autoderef + let _: u32 = (&3u8).try_into().unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + // test autoref + let _: u32 = 3.0.try_into().unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + let mut data = 3u16; + let mut_ptr = std::ptr::addr_of_mut!(data); + let _: u32 = mut_ptr.try_into().unwrap(); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + + type U32Alias = u32; + let _ = U32Alias::try_from(3u8).unwrap(); + //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! +} diff --git a/src/test/ui/rust-2021/future-prelude-collision.stderr b/src/test/ui/rust-2021/future-prelude-collision.stderr new file mode 100644 index 00000000000..190145ef4db --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision.stderr @@ -0,0 +1,79 @@ +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision.rs:54:18 + | +LL | let _: u32 = 3u8.try_into().unwrap(); + | ^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(3u8)` + | +note: the lint level is defined here + --> $DIR/future-prelude-collision.rs:4:9 + | +LL | #![warn(future_prelude_collision)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: trait-associated function `try_from` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision.rs:59:13 + | +LL | let _ = u32::try_from(3u8).unwrap(); + | ^^^^^^^^^^^^^ help: disambiguate the associated function: `<u32 as TryFromU8>::try_from` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: trait-associated function `from_iter` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision.rs:64:13 + | +LL | let _ = <Vec<u8>>::from_iter(vec![1u8, 2, 3, 4, 5, 6].into_iter()); + | ^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Vec<u8> as FromByteIterator>::from_iter` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: trait-associated function `try_from` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision.rs:72:18 + | +LL | let _: u32 = <_>::try_from(3u8).unwrap(); + | ^^^^^^^^^^^^^ help: disambiguate the associated function: `<_ as TryFromU8>::try_from` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision.rs:77:18 + | +LL | let _: u32 = (&3u8).try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(*(&3u8))` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision.rs:82:18 + | +LL | let _: u32 = 3.0.try_into().unwrap(); + | ^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(&3.0)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision.rs:88:18 + | +LL | let _: u32 = mut_ptr.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(mut_ptr as *const _)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: trait-associated function `try_from` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision.rs:93:13 + | +LL | let _ = U32Alias::try_from(3u8).unwrap(); + | ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<U32Alias as TryFromU8>::try_from` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: 8 warnings emitted + diff --git a/src/test/ui/rust-2021/generic-type-collision.fixed b/src/test/ui/rust-2021/generic-type-collision.fixed new file mode 100644 index 00000000000..00fb128a981 --- /dev/null +++ b/src/test/ui/rust-2021/generic-type-collision.fixed @@ -0,0 +1,18 @@ +// check-pass +// run-rustfix +// edition 2018 +#![warn(future_prelude_collision)] + +trait MyTrait<A> { + fn from_iter(x: Option<A>); +} + +impl<T> MyTrait<()> for Vec<T> { + fn from_iter(_: Option<()>) {} +} + +fn main() { + <Vec<i32> as MyTrait<_>>::from_iter(None); + //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! +} diff --git a/src/test/ui/rust-2021/generic-type-collision.rs b/src/test/ui/rust-2021/generic-type-collision.rs new file mode 100644 index 00000000000..406fba4d247 --- /dev/null +++ b/src/test/ui/rust-2021/generic-type-collision.rs @@ -0,0 +1,18 @@ +// check-pass +// run-rustfix +// edition 2018 +#![warn(future_prelude_collision)] + +trait MyTrait<A> { + fn from_iter(x: Option<A>); +} + +impl<T> MyTrait<()> for Vec<T> { + fn from_iter(_: Option<()>) {} +} + +fn main() { + <Vec<i32>>::from_iter(None); + //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 + //~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! +} diff --git a/src/test/ui/rust-2021/generic-type-collision.stderr b/src/test/ui/rust-2021/generic-type-collision.stderr new file mode 100644 index 00000000000..9374379d247 --- /dev/null +++ b/src/test/ui/rust-2021/generic-type-collision.stderr @@ -0,0 +1,16 @@ +warning: trait-associated function `from_iter` will become ambiguous in Rust 2021 + --> $DIR/generic-type-collision.rs:15:5 + | +LL | <Vec<i32>>::from_iter(None); + | ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Vec<i32> as MyTrait<_>>::from_iter` + | +note: the lint level is defined here + --> $DIR/generic-type-collision.rs:4:9 + | +LL | #![warn(future_prelude_collision)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: 1 warning emitted + diff --git a/src/test/ui/rust-2021/inherent-dyn-collision.fixed b/src/test/ui/rust-2021/inherent-dyn-collision.fixed new file mode 100644 index 00000000000..cbb6e9659df --- /dev/null +++ b/src/test/ui/rust-2021/inherent-dyn-collision.fixed @@ -0,0 +1,53 @@ +// Test case where the method we want is an inherent method on a +// dyn Trait. In that case, the fix is to insert `*` on the receiver. +// +// check-pass +// run-rustfix +// edition:2018 + +#![warn(future_prelude_collision)] + +trait TryIntoU32 { + fn try_into(&self) -> Result<u32, ()>; +} + +impl TryIntoU32 for u8 { + // note: &self + fn try_into(&self) -> Result<u32, ()> { + Ok(22) + } +} + +mod inner { + use super::get_dyn_trait; + + // note: this does nothing, but is copying from ffishim's problem of + // having a struct of the same name as the trait in-scope, while *also* + // implementing the trait for that struct but **without** importing the + // trait itself into scope + struct TryIntoU32; + + impl super::TryIntoU32 for TryIntoU32 { + fn try_into(&self) -> Result<u32, ()> { + Ok(0) + } + } + + // this is where the gross part happens. since `get_dyn_trait` returns + // a Box<dyn Trait>, it can still call the method for `dyn Trait` without + // `Trait` being in-scope. it might even be possible to make the trait itself + // entirely unreference-able from the callsite? + pub fn test() -> u32 { + (&*get_dyn_trait()).try_into().unwrap() + //~^ WARNING trait method `try_into` will become ambiguous + //~| WARNING this was previously accepted + } +} + +fn get_dyn_trait() -> Box<dyn TryIntoU32> { + Box::new(3u8) as Box<dyn TryIntoU32> +} + +fn main() { + dbg!(inner::test()); +} diff --git a/src/test/ui/rust-2021/inherent-dyn-collision.rs b/src/test/ui/rust-2021/inherent-dyn-collision.rs new file mode 100644 index 00000000000..1c9929eff91 --- /dev/null +++ b/src/test/ui/rust-2021/inherent-dyn-collision.rs @@ -0,0 +1,53 @@ +// Test case where the method we want is an inherent method on a +// dyn Trait. In that case, the fix is to insert `*` on the receiver. +// +// check-pass +// run-rustfix +// edition:2018 + +#![warn(future_prelude_collision)] + +trait TryIntoU32 { + fn try_into(&self) -> Result<u32, ()>; +} + +impl TryIntoU32 for u8 { + // note: &self + fn try_into(&self) -> Result<u32, ()> { + Ok(22) + } +} + +mod inner { + use super::get_dyn_trait; + + // note: this does nothing, but is copying from ffishim's problem of + // having a struct of the same name as the trait in-scope, while *also* + // implementing the trait for that struct but **without** importing the + // trait itself into scope + struct TryIntoU32; + + impl super::TryIntoU32 for TryIntoU32 { + fn try_into(&self) -> Result<u32, ()> { + Ok(0) + } + } + + // this is where the gross part happens. since `get_dyn_trait` returns + // a Box<dyn Trait>, it can still call the method for `dyn Trait` without + // `Trait` being in-scope. it might even be possible to make the trait itself + // entirely unreference-able from the callsite? + pub fn test() -> u32 { + get_dyn_trait().try_into().unwrap() + //~^ WARNING trait method `try_into` will become ambiguous + //~| WARNING this was previously accepted + } +} + +fn get_dyn_trait() -> Box<dyn TryIntoU32> { + Box::new(3u8) as Box<dyn TryIntoU32> +} + +fn main() { + dbg!(inner::test()); +} diff --git a/src/test/ui/rust-2021/inherent-dyn-collision.stderr b/src/test/ui/rust-2021/inherent-dyn-collision.stderr new file mode 100644 index 00000000000..3d7637100c2 --- /dev/null +++ b/src/test/ui/rust-2021/inherent-dyn-collision.stderr @@ -0,0 +1,16 @@ +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/inherent-dyn-collision.rs:41:9 + | +LL | get_dyn_trait().try_into().unwrap() + | ^^^^^^^^^^^^^^^ help: disambiguate the method call: `(&*get_dyn_trait())` + | +note: the lint level is defined here + --> $DIR/inherent-dyn-collision.rs:8:9 + | +LL | #![warn(future_prelude_collision)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684> + +warning: 1 warning emitted + diff --git a/src/test/ui/rust-2021/inherent-method-collision.rs b/src/test/ui/rust-2021/inherent-method-collision.rs new file mode 100644 index 00000000000..c638351d5fc --- /dev/null +++ b/src/test/ui/rust-2021/inherent-method-collision.rs @@ -0,0 +1,15 @@ +// Test that we do NOT warn for inherent methods invoked via `T::` form. +// +// check-pass + +#![deny(future_prelude_collision)] + +pub struct MySeq {} + +impl MySeq { + pub fn from_iter(_: impl IntoIterator<Item = u32>) {} +} + +fn main() { + MySeq::from_iter(Some(22)); +} |
