diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 3257fc3437273..7cce8a2a46269 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -50,7 +50,7 @@ pub(crate) fn expand_deriving_clone( } } ItemKind::Union(..) => { - bounds = smallvec![Path(path_std!(marker::Copy))]; + bounds = smallvec![path_std!(cx, span, marker::Copy)]; is_simple = true; substructure = combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, true)); } @@ -62,7 +62,7 @@ pub(crate) fn expand_deriving_clone( if is_simple { let trivial_def = TraitDef { span, - path: path_std!(clone::TrivialClone), + path: path_std!(cx, span, clone::TrivialClone), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, additional_bounds: bounds.clone(), @@ -81,7 +81,7 @@ pub(crate) fn expand_deriving_clone( let trait_def = TraitDef { span, - path: path_std!(clone::Clone), + path: path_std!(cx, span, clone::Clone), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, additional_bounds: bounds, @@ -149,7 +149,7 @@ fn cs_clone_simple( &[sym::clone, sym::AssertParamIsCopy], ); } else { - match substr.fields { + match substr { StaticStruct(vdata, ..) => { process_variant(vdata); } @@ -171,17 +171,18 @@ fn cs_clone(cx: &ExtCtxt<'_>, trait_span: Span, substr: Substructure<'_>) -> Blo cx.expr_call_global(field.span, fn_path.clone(), args) }; + let self_ident = Ident::new(kw::SelfUpper, trait_span); let ctor_path; let all_fields; let vdata; - match substr.fields { + match substr { Struct(vdata_, af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident]); + ctor_path = cx.path(trait_span, vec![self_ident]); all_fields = af; vdata = vdata_; } EnumMatching(.., variant, af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.ident]); + ctor_path = cx.path(trait_span, vec![self_ident, variant.ident]); all_fields = af; vdata = &variant.data; } diff --git a/compiler/rustc_builtin_macros/src/deriving/const_param_ty.rs b/compiler/rustc_builtin_macros/src/deriving/const_param_ty.rs index 8034a3e9b0b16..69041a60027d3 100644 --- a/compiler/rustc_builtin_macros/src/deriving/const_param_ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/const_param_ty.rs @@ -14,10 +14,10 @@ pub(crate) fn expand_deriving_const_param_ty( ) { let trait_def = TraitDef { span, - path: path_std!(marker::ConstParamTy_), + path: path_std!(cx, span, marker::ConstParamTy_), skip_path_as_bound: false, needs_copy_as_bound_if_packed: false, - additional_bounds: smallvec![ty::Ty::Path(path_std!(cmp::Eq))], + additional_bounds: smallvec![path_std!(cx, span, cmp::Eq)], supports_unions: false, methods: SmallVec::new(), associated_types: SmallVec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/copy.rs b/compiler/rustc_builtin_macros/src/deriving/copy.rs index bae4bd98df465..5badeb7e1877e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/copy.rs +++ b/compiler/rustc_builtin_macros/src/deriving/copy.rs @@ -14,7 +14,7 @@ pub(crate) fn expand_deriving_copy( ) { let trait_def = TraitDef { span, - path: path_std!(marker::Copy), + path: path_std!(cx, span, marker::Copy), skip_path_as_bound: false, needs_copy_as_bound_if_packed: false, additional_bounds: SmallVec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index e694502d607e8..66e9b3ed82bcc 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -16,11 +16,11 @@ pub(crate) fn expand_deriving_debug( is_const: bool, ) { // &mut ::std::fmt::Formatter - let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut); + let fmtr = Ref(Box::new(Path(path_std!(cx, span, fmt::Formatter))), ast::Mutability::Mut); let trait_def = TraitDef { span, - path: path_std!(fmt::Debug), + path: path_std!(cx, span, fmt::Debug), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, additional_bounds: SmallVec::new(), @@ -30,11 +30,16 @@ pub(crate) fn expand_deriving_debug( generics: cx.empty_generics(span), explicit_self: true, nonself_args: smallvec![(fmtr, sym::character('f'))], - ret_ty: Path(path_std!(fmt::Result)), + ret_ty: Path(path_std!(cx, span, fmt::Result)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless, - combine_substructure: combine_substructure(show_substructure), + combine_substructure: combine_substructure(|cx, span, substr| show_substructure( + cx, + span, + substr, + item.kind.ident().unwrap() + )), }], associated_types: SmallVec::new(), is_const, @@ -44,24 +49,30 @@ pub(crate) fn expand_deriving_debug( trait_def.expand(cx, item, push) } -fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: Substructure<'_>) -> BlockOrExpr { - // We want to make sure we have the ctxt set so that we can use unstable methods - let span = cx.with_def_site_ctxt(span); +fn formatter_ident(cx: &ExtCtxt<'_>, span: Span) -> Box { + cx.expr_ident(span, Ident::new(sym::character('f'), span)) +} +fn show_substructure( + cx: &ExtCtxt<'_>, + span: Span, + substr: Substructure<'_>, + type_ident: Ident, +) -> BlockOrExpr { let fmt_detail = cx.sess.opts.unstable_opts.fmt_debug; if fmt_detail == FmtDebug::None { return BlockOrExpr::new_expr(cx.expr_ok(span, cx.expr_tuple(span, ThinVec::new()))); } - let (ident, vdata, fields) = match substr.fields { - Struct(vdata, fields) => (substr.type_ident, vdata, fields), + let (ident, vdata, fields) = match substr { + Struct(vdata, fields) => (type_ident, vdata, fields), EnumMatching(v, fields) => (v.ident, &v.data, fields), - AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr), + AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, type_ident), _ => cx.dcx().span_bug(span, "unexpected substructure in `derive(Debug)`"), }; let name = cx.expr_str(span, ident.name); - let fmt = substr.nonselflike_args[0].clone(); + let fmt = formatter_ident(cx, span); // Fieldless enums have been special-cased earlier if fmt_detail == FmtDebug::Shallow { @@ -85,13 +96,14 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: Substructure<'_>) -> // The number of fields that can be handled without an array. const CUTOFF: usize = 5; - let expr_for_field = |field: &FieldInfo, index: usize| -> Box { - if index < fields.len() - 1 { - field.self_expr.clone() + let len = fields.len(); + let expr_for_field = |field: FieldInfo, index: usize| -> Box { + if index < len - 1 { + field.self_expr } else { // Unsized types need an extra indirection, but only the last field // may be unsized. - cx.expr_addr_of(field.span, field.self_expr.clone()) + cx.expr_addr_of(field.span, field.self_expr) } }; @@ -111,8 +123,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: Substructure<'_>) -> let mut args = ThinVec::with_capacity(2 + fields.len() * args_per_field); args.extend([fmt, name]); - for i in 0..fields.len() { - let field = &fields[i]; + for (i, field) in fields.into_iter().enumerate() { if is_struct { let name = cx.expr_str(field.span, field.name.unwrap().name); args.push(name); @@ -128,8 +139,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: Substructure<'_>) -> let mut name_exprs = ThinVec::with_capacity(fields.len()); let mut value_exprs = ThinVec::with_capacity(fields.len()); - for i in 0..fields.len() { - let field = &fields[i]; + for (i, field) in fields.into_iter().enumerate() { if is_struct { name_exprs.push(cx.expr_str(field.span, field.name.unwrap().name)); } @@ -216,14 +226,14 @@ fn show_fieldless_enum( cx: &ExtCtxt<'_>, span: Span, def: &EnumDef, - substr: Substructure<'_>, + type_ident: Ident, ) -> BlockOrExpr { - let fmt = substr.nonselflike_args[0].clone(); + let fmt = formatter_ident(cx, span); let arms = def .variants .iter() .map(|v| { - let variant_path = cx.path(span, vec![substr.type_ident, v.ident]); + let variant_path = cx.path(span, vec![type_ident, v.ident]); let pat = match &v.data { ast::VariantData::Tuple(fields, _) => { debug_assert!(fields.is_empty()); diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index f9f9af4e9f012..866ffc74da436 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -22,7 +22,7 @@ pub(crate) fn expand_deriving_default( let trait_def = TraitDef { span, - path: Path::new(vec![kw::Default, sym::Default]), + path: new_path(cx, span, &[kw::Default, sym::Default], &[]), skip_path_as_bound: has_a_default_variant(item), needs_copy_as_bound_if_packed: false, additional_bounds: SmallVec::new(), @@ -36,9 +36,9 @@ pub(crate) fn expand_deriving_default( attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: combine_substructure(|cx, trait_span, substr| { - match substr.fields { + match substr { StaticStruct(variant_data) => { - default_struct_substructure(cx, trait_span, substr, variant_data) + default_struct_substructure(cx, trait_span, variant_data) } StaticEnum(enum_def) => { default_enum_substructure(cx, trait_span, enum_def, item.span) @@ -66,26 +66,23 @@ fn default_call(cx: &ExtCtxt<'_>, span: Span) -> Box { fn default_struct_substructure( cx: &ExtCtxt<'_>, trait_span: Span, - substr: Substructure<'_>, variant_data: &VariantData, ) -> BlockOrExpr { let expr = match variant_data { - VariantData::Unit(_) => cx.expr_ident(trait_span, substr.type_ident), + VariantData::Unit(_) => cx.expr_ident(trait_span, Ident::new(kw::SelfUpper, trait_span)), VariantData::Tuple(fields, _) => { let exprs = fields .iter() .map(|field| default_call(cx, field.span.with_ctxt(trait_span.ctxt()))) .collect(); - cx.expr_call_ident(trait_span, substr.type_ident, exprs) + cx.expr_call_ident(trait_span, Ident::new(kw::SelfUpper, trait_span), exprs) } VariantData::Struct { fields, .. } => { let default_fields = fields .iter() .map(|field| { let span = field.span.with_ctxt(trait_span.ctxt()); - let value = if let Some(extras) = &field.extras - && let Some(default_val) = &extras.default - { + let value = if let Some(default_val) = field.default_value() { // We use the field default const expression. cx.expr( default_val.value.span, @@ -98,7 +95,7 @@ fn default_struct_substructure( cx.field_imm(span, field.ident.unwrap(), value) }) .collect(); - cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) + cx.expr_struct_ident(trait_span, Ident::new(kw::SelfUpper, trait_span), default_fields) } }; BlockOrExpr::new_expr(expr) diff --git a/compiler/rustc_builtin_macros/src/deriving/eq.rs b/compiler/rustc_builtin_macros/src/deriving/eq.rs index eaf9298fc10c7..1083b37cbf248 100644 --- a/compiler/rustc_builtin_macros/src/deriving/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/eq.rs @@ -19,7 +19,7 @@ pub(crate) fn expand_deriving_eq( let trait_def = TraitDef { span, - path: path_std!(cmp::Eq), + path: path_std!(cx, span, cmp::Eq), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, additional_bounds: SmallVec::new(), @@ -73,7 +73,7 @@ fn cs_total_eq_assert(cx: &ExtCtxt<'_>, trait_span: Span, substr: Substructure<' } }; - match substr.fields { + match substr { StaticStruct(vdata, ..) => { process_variant(vdata); } diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index 0b28df9850097..64cc917302935 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -5,7 +5,7 @@ use rustc_expand::base::{DummyResult, ExtCtxt}; use rustc_span::{Ident, Span, kw, sym}; use thin_vec::thin_vec; -use crate::deriving::generic::ty::{Path, PathKind, Ty}; +use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::pathvec; use crate::diagnostics; @@ -52,8 +52,7 @@ pub(crate) fn expand_deriving_from( Err(guar) => cx.ty(span, ast::TyKind::Err(guar)), }); - let path = - Path::new_(pathvec!(convert::From), vec![Box::new(from_type.clone())], PathKind::Std); + let path = new_path(cx, span, pathvec!(convert::From), &[from_type.clone()]); // Generate code like this: // @@ -89,8 +88,8 @@ pub(crate) fn expand_deriving_from( }; let self_kw = Ident::new(kw::SelfUpper, span); - let expr: Box = match substructure.fields { - SubstructureFields::StaticStruct(variant) => match variant { + let expr: Box = match substructure { + StaticStruct(variant) => match variant { // Self { field: value } VariantData::Struct { .. } => cx.expr_struct_ident( span, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 39bfaf40681c6..b6bd482945546 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -174,10 +174,11 @@ //! ) //! ``` +use std::iter::once; use std::ops::Not; use std::{iter, vec}; -pub(crate) use SubstructureFields::*; +pub(crate) use Substructure::*; pub(crate) use rustc_ast as ast; use rustc_ast::token::{IdentKind, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree}; @@ -191,7 +192,7 @@ use rustc_expand::base::ExtCtxt; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, respan, sym}; pub(crate) use smallvec::{SmallVec, smallvec}; use thin_vec::{ThinVec, thin_vec}; -use ty::{Path, Ref, Self_, Ty}; +use ty::{Ref, Self_, Ty}; use crate::{deriving, diagnostics}; @@ -202,7 +203,7 @@ pub(crate) struct TraitDef<'a> { pub span: Span, /// Path of the trait, including any type parameters - pub path: Path, + pub path: ast::Path, /// Whether to skip adding the current trait as a bound to the type parameters of the type. pub skip_path_as_bound: bool, @@ -212,7 +213,7 @@ pub(crate) struct TraitDef<'a> { /// Additional bounds required of any type parameters of the type, /// other than the current trait - pub additional_bounds: SmallVec<[Ty; 1]>, + pub additional_bounds: SmallVec<[ast::Path; 1]>, /// Can this trait be derived for unions? pub supports_unions: bool, @@ -268,16 +269,6 @@ pub(crate) enum FieldlessVariantsStrategy { SpecializeIfAllVariantsFieldless, } -/// All the data about the data structure/method being derived upon. -pub(crate) struct Substructure<'a> { - /// ident of self - pub type_ident: Ident, - /// Verbatim access to any non-selflike arguments, i.e. arguments that - /// don't have type `&Self`. - pub nonselflike_args: &'a [Box], - pub fields: SubstructureFields<'a>, -} - /// Summary of the relevant parts of a struct/enum field. pub(crate) struct FieldInfo { pub span: Span, @@ -287,14 +278,14 @@ pub(crate) struct FieldInfo { /// The expression corresponding to this field of `self` /// (specifically, a reference to it). pub self_expr: Box, - /// The expressions corresponding to references to this field in - /// the other selflike arguments. - pub other_selflike_exprs: Vec>, + /// The expression corresponding to a reference to this field in + /// the other selflike argument. + pub other_selflike_expr: Option>, pub maybe_scalar: bool, } /// A summary of the possible sets of fields. -pub(crate) enum SubstructureFields<'a> { +pub(crate) enum Substructure<'a> { /// A non-static method where `Self` is a struct. Struct(&'a ast::VariantData, Vec), @@ -571,8 +562,6 @@ impl<'a> TraitDef<'a> { methods: impl Iterator>, is_packed: bool, ) -> Box { - let trait_path = self.path.to_path(cx, self.span); - // Transform associated types from `deriving::ty::Ty` into `ast::AssocItem` let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| { Box::new(ast::AssocItem { @@ -613,11 +602,11 @@ impl<'a> TraitDef<'a> { let bounds: ThinVec<_> = self .additional_bounds .iter() - .map(|p| cx.trait_bound(p.to_path(cx, span), self.is_const)) + .map(|p| cx.trait_bound(ast::Path { span, ..p.clone() }, self.is_const)) .chain( // Add a bound for the current trait. self.skip_path_as_bound.not().then(|| { - let mut trait_path = trait_path.clone(); + let mut trait_path = self.path.clone(); trait_path.span = span; cx.trait_bound(trait_path, self.is_const) }), @@ -625,8 +614,8 @@ impl<'a> TraitDef<'a> { .chain({ // Add a `Copy` bound if required. if is_packed && self.needs_copy_as_bound_if_packed { - let p = deriving::path_std!(marker::Copy); - Some(cx.trait_bound(p.to_path(cx, span), self.is_const)) + let p = deriving::path_std!(cx, span, marker::Copy); + Some(cx.trait_bound(p, self.is_const)) } else { None } @@ -692,18 +681,18 @@ impl<'a> TraitDef<'a> { let mut bounds: ThinVec<_> = self .additional_bounds .iter() - .map(|p| cx.trait_bound(p.to_path(cx, self.span), self.is_const)) + .map(|p| cx.trait_bound(p.clone(), self.is_const)) .collect(); // Require the current trait. if !self.skip_path_as_bound { - bounds.push(cx.trait_bound(trait_path.clone(), self.is_const)); + bounds.push(cx.trait_bound(self.path.clone(), self.is_const)); } // Add a `Copy` bound if required. if is_packed && self.needs_copy_as_bound_if_packed { - let p = deriving::path_std!(marker::Copy); - bounds.push(cx.trait_bound(p.to_path(cx, self.span), self.is_const)); + let p = deriving::path_std!(cx, self.span, marker::Copy); + bounds.push(cx.trait_bound(p, self.is_const)); } if !bounds.is_empty() { @@ -730,7 +719,7 @@ impl<'a> TraitDef<'a> { let trait_generics = Generics { params, where_clause, span }; // Create the reference to the trait. - let trait_ref = cx.trait_ref(trait_path); + let trait_ref = cx.trait_ref(self.path.clone()); let self_params: Vec<_> = generics .params @@ -826,27 +815,10 @@ impl<'a> TraitDef<'a> { let field_tys = struct_def.fields().iter().map(|field| &*field.ty); let methods = self.methods.iter().filter_map(|method_def| { - let ArgDetails { selflike_args, nonselflike_args } = - method_def.extract_arg_details(cx, self); - let body = if from_scratch || method_def.is_static() { - method_def.call_substructure_method( - cx, - self, - type_ident, - &nonselflike_args, - StaticStruct(struct_def), - ) + method_def.call_substructure_method(cx, self, StaticStruct(struct_def)) } else { - method_def.expand_struct_method_body( - cx, - self, - struct_def, - type_ident, - &selflike_args, - &nonselflike_args, - is_packed, - ) + method_def.expand_struct_method_body(cx, self, struct_def, is_packed) }; method_def.create_method(cx, self, body) @@ -870,26 +842,10 @@ impl<'a> TraitDef<'a> { .map(|field| &*field.ty); let methods = self.methods.iter().filter_map(|method_def| { - let ArgDetails { selflike_args, nonselflike_args } = - method_def.extract_arg_details(cx, self); - let body = if from_scratch || method_def.is_static() { - method_def.call_substructure_method( - cx, - self, - type_ident, - &nonselflike_args, - StaticEnum(enum_def), - ) + method_def.call_substructure_method(cx, self, StaticEnum(enum_def)) } else { - method_def.expand_enum_method_body( - cx, - self, - enum_def, - type_ident, - selflike_args, - &nonselflike_args, - ) + method_def.expand_enum_method_body(cx, self, enum_def, type_ident) }; method_def.create_method(cx, self, body) @@ -900,56 +856,33 @@ impl<'a> TraitDef<'a> { } } -struct ArgDetails { - /// Expressions for `&self` (if present) and also any other - /// args with the same type (e.g. the `other` arg in `PartialEq::eq`). - selflike_args: ThinVec>, - /// Expressions for all the remaining args. - nonselflike_args: Vec>, -} - impl<'a> MethodDef<'a> { fn call_substructure_method( &self, cx: &ExtCtxt<'_>, trait_: &TraitDef<'_>, - type_ident: Ident, - nonselflike_args: &[Box], - fields: SubstructureFields<'_>, + substructure: Substructure<'_>, ) -> BlockOrExpr { - let span = trait_.span; - let substructure = Substructure { type_ident, nonselflike_args, fields }; - let f: &CombineSubstructureFunc<'_> = &self.combine_substructure; - f(cx, span, substructure) + (self.combine_substructure)(cx, trait_.span, substructure) } fn is_static(&self) -> bool { !self.explicit_self } - fn extract_arg_details(&self, cx: &ExtCtxt<'_>, trait_: &TraitDef<'_>) -> ArgDetails { - let mut selflike_args = ThinVec::new(); - let mut nonselflike_args = Vec::new(); - let span = trait_.span; - - if self.explicit_self { - // This constructs a fresh `self` path. - selflike_args.push(cx.expr_self(span)); - } - - for (ty, name) in self.nonself_args.iter() { - let ident = Ident::new(*name, span); - let arg_expr = cx.expr_ident(span, ident); + /// Expressions for `&self` and also any other + /// args with the same type (e.g. the `other` arg in `PartialEq::eq`). + fn get_selflike_args(&self, cx: &ExtCtxt<'_>, trait_: &TraitDef<'_>) -> ThinVec> { + assert!(self.explicit_self); - match ty { - // Selflike (`&Self`) arguments only occur in non-static methods. - Ref(Self_, _) if self.explicit_self => selflike_args.push(arg_expr), - Self_ => cx.dcx().span_bug(span, "`Self` in non-return position"), - _ => nonselflike_args.push(arg_expr), - } - } + let span = trait_.span; - ArgDetails { selflike_args, nonselflike_args } + once(cx.expr_self(span)) + .chain(self.nonself_args.iter().filter_map(|(ty, name)| match ty { + Ref(Self_, _) => Some(cx.expr_ident(span, Ident::new(*name, span))), + _ => None, + })) + .collect() } fn create_method( @@ -1058,22 +991,13 @@ impl<'a> MethodDef<'a> { cx: &ExtCtxt<'_>, trait_: &TraitDef<'b>, struct_def: &'b VariantData, - type_ident: Ident, - selflike_args: &[Box], - nonselflike_args: &[Box], is_packed: bool, ) -> BlockOrExpr { - assert!(selflike_args.len() == 1 || selflike_args.len() == 2); + let selflike_args = self.get_selflike_args(cx, trait_); let selflike_fields = - trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed); - self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - Struct(struct_def, selflike_fields), - ) + trait_.create_struct_field_access_fields(cx, &selflike_args, struct_def, is_packed); + self.call_substructure_method(cx, trait_, Struct(struct_def, selflike_fields)) } /// ``` @@ -1117,14 +1041,7 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'b>, enum_def: &'b EnumDef, type_ident: Ident, - mut selflike_args: ThinVec>, - nonselflike_args: &[Box], ) -> BlockOrExpr { - assert!( - !selflike_args.is_empty(), - "static methods must use `expand_static_enum_method_body`", - ); - let span = trait_.span; let variants = &enum_def.variants; @@ -1136,13 +1053,14 @@ impl<'a> MethodDef<'a> { // `match *self {}`. This produces machine code identical to `unsafe { // core::intrinsics::unreachable() }` while being safe and stable. if variants.is_empty() { - selflike_args.truncate(1); - let match_arg = cx.expr_deref(span, selflike_args.pop().unwrap()); + let match_arg = cx.expr_deref(span, cx.expr_self(span)); let match_arms = ThinVec::new(); let expr = cx.expr_match(span, match_arg, match_arms); return BlockOrExpr(ThinVec::new(), Some(expr)); } + let selflike_args = self.get_selflike_args(cx, trait_); + let prefixes = iter::once("__self".to_string()) .chain((1..selflike_args.len()).map(|arg_count| format!("__arg{arg_count}"))) .collect::>(); @@ -1164,9 +1082,11 @@ impl<'a> MethodDef<'a> { discr_idents.clone().map(|ident| cx.expr_addr_of(span, cx.expr_ident(span, ident))); let self_expr = discr_exprs.next().unwrap(); - let other_selflike_exprs = discr_exprs.collect(); + let other_selflike_expr = discr_exprs.next(); + debug_assert!(discr_exprs.next().is_none()); + let discr_field = - FieldInfo { span, name: None, self_expr, other_selflike_exprs, maybe_scalar: true }; + FieldInfo { span, name: None, self_expr, other_selflike_expr, maybe_scalar: true }; let discr_let_stmts: ThinVec<_> = iter::zip(discr_idents, &selflike_args) .map(|(ident, selflike_arg)| { @@ -1194,13 +1114,8 @@ impl<'a> MethodDef<'a> { // there are multiple variants, we need just an operation on // the discriminant(s). let (discr_field, mut discr_let_stmts) = get_discr_pieces(); - let mut discr_check = self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - EnumDiscr(discr_field, None), - ); + let mut discr_check = + self.call_substructure_method(cx, trait_, EnumDiscr(discr_field, None)); discr_let_stmts.append(&mut discr_check.0); return BlockOrExpr(discr_let_stmts, discr_check.1); } @@ -1208,8 +1123,6 @@ impl<'a> MethodDef<'a> { return self.call_substructure_method( cx, trait_, - type_ident, - nonselflike_args, AllFieldlessEnum(enum_def), ); } @@ -1221,8 +1134,6 @@ impl<'a> MethodDef<'a> { return self.call_substructure_method( cx, trait_, - type_ident, - nonselflike_args, EnumMatching(variant, Vec::new()), ); } @@ -1263,15 +1174,8 @@ impl<'a> MethodDef<'a> { // Self arg, assuming all are instances of VariantK. // Build up code associated with such a case. let substructure = EnumMatching(variant, fields); - let arm_expr = self - .call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - substructure, - ) - .into_expr(cx, span); + let arm_expr = + self.call_substructure_method(cx, trait_, substructure).into_expr(cx, span); cx.arm(span, single_pat, arm_expr) }) @@ -1285,14 +1189,8 @@ impl<'a> MethodDef<'a> { // variants. The index and actual variant aren't meaningful in // this case, so just use dummy values. Some( - self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - EnumMatching(v, Vec::new()), - ) - .into_expr(cx, span), + self.call_substructure_method(cx, trait_, EnumMatching(v, Vec::new())) + .into_expr(cx, span), ) } _ if variants.len() > 1 && selflike_args.len() > 1 => { @@ -1334,8 +1232,6 @@ impl<'a> MethodDef<'a> { let mut discr_check_plus_match = self.call_substructure_method( cx, trait_, - type_ident, - nonselflike_args, EnumDiscr(discr_field, Some(get_match_expr(selflike_args))), ); discr_let_stmts.append(&mut discr_check_plus_match.0); @@ -1404,15 +1300,15 @@ impl<'a> TraitDef<'a> { .map(|(i, struct_field)| { // For this field, get an expr for each selflike_arg. E.g. for // `PartialEq::eq`, one for each of `&self` and `other`. - let sp = struct_field.span.with_ctxt(self.span.ctxt()); - let mut exprs: Vec<_> = mk_exprs(i, struct_field, sp); + let span = struct_field.span.with_ctxt(self.span.ctxt()); + let mut exprs: Vec<_> = mk_exprs(i, struct_field, span); let self_expr = exprs.remove(0); - let other_selflike_exprs = exprs; + debug_assert!(exprs.len() <= 1); FieldInfo { - span: sp.with_ctxt(self.span.ctxt()), + span, name: struct_field.ident, self_expr, - other_selflike_exprs, + other_selflike_expr: exprs.pop(), maybe_scalar: struct_field.ty.peel_refs().kind.maybe_scalar(), } }) @@ -1493,7 +1389,7 @@ pub(crate) fn cs_foldr( // The fallback case for a struct or enum variant with no fields. fieldless: impl Fn() -> Box, ) -> Box { - match substructure.fields { + match substructure { EnumMatching(.., all_fields) | Struct(_, all_fields) => { let mut fields = all_fields.into_iter(); let base_field = fields.next_back(); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 9efe0b109f17d..8f2de7a46fa18 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -4,50 +4,18 @@ use std::iter::once; pub(crate) use Ty::*; -use rustc_ast::{self as ast, GenericArg, TyKind}; +use rustc_ast::{self as ast, GenericArg}; use rustc_expand::base::ExtCtxt; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw}; +use rustc_span::{Ident, Span, Symbol, kw}; use thin_vec::ThinVec; -/// A path, e.g., `::std::option::Option::` (global). Has support -/// for type parameters. -#[derive(Clone)] -pub(crate) struct Path { - path: Vec, - params: Vec>, - kind: PathKind, -} - -#[derive(Clone)] -pub(crate) enum PathKind { - Local, - Std, -} - -impl Path { - pub(crate) fn new(path: Vec) -> Path { - Path::new_(path, Vec::new(), PathKind::Std) - } - pub(crate) fn new_local(path: Symbol) -> Path { - Path::new_(vec![path], Vec::new(), PathKind::Local) - } - pub(crate) fn new_(path: Vec, params: Vec>, kind: PathKind) -> Path { - Path { path, params, kind } - } - - pub(crate) fn to_path(&self, cx: &ExtCtxt<'_>, span: Span) -> ast::Path { - let idents = self.path.iter().map(|s| Ident::new(*s, span)); - let tys = self.params.iter().map(|t| t.to_ty(cx, span)); - let params = tys.map(GenericArg::Type).collect(); +pub(crate) fn new_path(cx: &ExtCtxt<'_>, span: Span, path: &[Symbol], params: &[Ty]) -> ast::Path { + let idents = path.iter().map(|s| Ident::new(*s, span)); + let tys = params.iter().map(|t| t.to_ty(cx, span)); + let params = tys.map(GenericArg::Type).collect(); - let idents = if let PathKind::Std = self.kind { - let def_site = cx.with_def_site_ctxt(DUMMY_SP); - once(Ident::new(kw::DollarCrate, def_site)).chain(idents).collect() - } else { - idents.collect() - }; - cx.path_all(span, false, idents, params) - } + let idents = once(Ident::new(kw::DollarCrate, span)).chain(idents).collect(); + cx.path_all(span, false, idents, params) } /// A type. Supports pointers, Self, literals, unit or an arbitrary AST path. @@ -58,7 +26,7 @@ pub(crate) enum Ty { Ref(Box, ast::Mutability), /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type /// parameter, and things like `i32` - Path(Path), + Path(ast::Path), /// For () return types. Unit, /// An arbitrary type. @@ -76,26 +44,10 @@ impl Ty { let raw_ty = ty.to_ty(cx, span); cx.ty_ref(span, raw_ty, None, *mutbl) } - Path(p) => cx.ty_path(p.to_path(cx, span)), - Self_ => cx.ty_path(self.to_path(cx, span)), - Unit => { - let ty = ast::TyKind::Tup(ThinVec::new()); - cx.ty(span, ty) - } + Path(p) => cx.ty_path(p.clone()), + Self_ => cx.ty_path(cx.path_ident(span, Ident::new(kw::SelfUpper, span))), + Unit => cx.ty(span, ast::TyKind::Tup(ThinVec::new())), AstTy(ty) => ty.clone(), } } - - pub(crate) fn to_path(&self, cx: &ExtCtxt<'_>, span: Span) -> ast::Path { - match self { - Self_ => cx.path_ident(span, Ident::new(kw::SelfUpper, span)), - Path(p) => p.to_path(cx, span), - AstTy(ty) => match &ty.kind { - TyKind::Path(_, path) => path.clone(), - _ => cx.dcx().span_bug(span, "non-path in a path in generic `derive`"), - }, - Ref(..) => cx.dcx().span_bug(span, "ref in a path in generic `derive`"), - Unit => cx.dcx().span_bug(span, "unit in a path in generic `derive`"), - } - } } diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index b6a87851254fc..55c1d338c5d2d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -14,15 +14,15 @@ pub(crate) fn expand_deriving_hash( push: &mut dyn FnMut(Box), is_const: bool, ) { - let path = path_std!(hash::Hash); + let path = path_std!(cx, span, hash::Hash); - let typaram = sym::__H; + let typaram = Ident::new(sym::__H, span); - let arg = Path::new_local(typaram); + let arg = cx.path_ident(span, typaram); let param = { - let path = cx.path_all(span, false, cx.std_path(&[sym::hash, sym::Hasher]), Vec::new()); - cx.typaram(span, Ident::new(typaram, span), thin_vec![cx.trait_bound(path, false)], None) + let path = path_std!(cx, span, hash::Hasher); + cx.typaram(span, typaram, thin_vec![cx.trait_bound(path, false)], None) }; let generics = ast::Generics { @@ -58,24 +58,25 @@ pub(crate) fn expand_deriving_hash( } fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: Substructure<'_>) -> BlockOrExpr { - let [state_expr] = substr.nonselflike_args else { - cx.dcx().span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`"); - }; let call_hash = |span, expr| { let strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]); let hash_path = cx.expr_path(cx.path_global(span, strs)); - let expr = cx.expr_call(span, hash_path, thin_vec![expr, state_expr.clone()]); + let expr = cx.expr_call( + span, + hash_path, + thin_vec![expr, cx.expr_ident(span, Ident::new(sym::state, span))], + ); cx.stmt_expr(expr) }; - let (stmts, match_expr) = match substr.fields { + let (stmts, match_expr) = match substr { Struct(_, fields) | EnumMatching(.., fields) => { let stmts = fields.into_iter().map(|field| call_hash(field.span, field.self_expr)).collect(); (stmts, None) } EnumDiscr(discr_field, match_expr) => { - assert!(discr_field.other_selflike_exprs.is_empty()); + assert!(discr_field.other_selflike_expr.is_none()); let stmts = thin_vec![call_hash(discr_field.span, discr_field.self_expr)]; (stmts, match_expr) } diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index a1b1d56664f22..66d4a61b97fdc 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -7,11 +7,11 @@ use rustc_span::{Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; macro pathvec($($rest:ident)::+) {{ - vec![ $( sym::$rest ),+ ] + &[ $( sym::$rest ),+ ] }} -macro path_std($($x:tt)*) { - generic::ty::Path::new( pathvec!( $($x)* ) ) +macro path_std($cx: expr, $span: expr, $($x:tt)*) { + generic::ty::new_path($cx, $span, pathvec!( $($x)* ), &[] ) } pub(crate) mod clone; diff --git a/compiler/rustc_builtin_macros/src/deriving/ord.rs b/compiler/rustc_builtin_macros/src/deriving/ord.rs index 663e9b86a9ebe..426fa41a3b6d4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/ord.rs @@ -16,7 +16,7 @@ pub(crate) fn expand_deriving_ord( ) { let trait_def = TraitDef { span, - path: path_std!(cmp::Ord), + path: path_std!(cx, span, cmp::Ord), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, additional_bounds: SmallVec::new(), @@ -26,7 +26,7 @@ pub(crate) fn expand_deriving_ord( generics: cx.empty_generics(span), explicit_self: true, nonself_args: smallvec![(self_ref(), sym::other)], - ret_ty: Path(path_std!(cmp::Ordering)), + ret_ty: Path(path_std!(cx, span, cmp::Ordering)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(cs_cmp), @@ -57,10 +57,9 @@ pub(crate) fn cs_cmp(cx: &ExtCtxt<'_>, span: Span, substr: Substructure<'_>) -> span, substr, |field| { - let [other_expr] = &field.other_selflike_exprs[..] else { - cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); - }; - let args = thin_vec![field.self_expr.clone(), other_expr.clone()]; + let other_expr = + field.other_selflike_expr.expect("not exactly 2 arguments in `derive(Ord)`"); + let args = thin_vec![field.self_expr, other_expr]; cx.expr_call_global(field.span, cmp_path.clone(), args) }, |span, expr1, expr2| { diff --git a/compiler/rustc_builtin_macros/src/deriving/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/partial_eq.rs index be48c0532e596..5c8a6225fa91b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/partial_eq.rs @@ -1,10 +1,10 @@ use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, Mutability, Safety}; use rustc_expand::base::ExtCtxt; -use rustc_span::{Span, sym}; +use rustc_span::{Ident, Span, sym}; use thin_vec::thin_vec; use crate::deriving::generic::ty::*; -use crate::deriving::generic::{self, *}; +use crate::deriving::generic::*; use crate::deriving::path_std; /// Expands a `#[derive(PartialEq)]` attribute into an implementation for the @@ -18,13 +18,13 @@ pub(crate) fn expand_deriving_partial_eq( ) { let structural_trait_def = TraitDef { span, - path: path_std!(marker::StructuralPartialEq), + path: path_std!(cx, span, marker::StructuralPartialEq), skip_path_as_bound: true, // crucial! needs_copy_as_bound_if_packed: false, // The `StructuralPartialEq` impl must have the *same* bounds as the `PartialEq` impl, // or it will apply in situations where it should not, such as in the bug // . - additional_bounds: smallvec![ty::Ty::Path(path_std!(cmp::PartialEq))], + additional_bounds: smallvec![path_std!(cx, span, cmp::PartialEq)], // We really don't support unions, but that's already checked by the impl generated below; // a second check here would lead to redundant error messages. supports_unions: true, @@ -43,7 +43,7 @@ pub(crate) fn expand_deriving_partial_eq( generics: cx.empty_generics(span), explicit_self: true, nonself_args: smallvec![(self_ref(), sym::other)], - ret_ty: Path(generic::ty::Path::new_local(sym::bool)), + ret_ty: Path(cx.path_ident(span, Ident::new(sym::bool, span))), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(get_substructure_equality_expr), @@ -51,7 +51,7 @@ pub(crate) fn expand_deriving_partial_eq( let trait_def = TraitDef { span, - path: path_std!(cmp::PartialEq), + path: path_std!(cx, span, cmp::PartialEq), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, additional_bounds: SmallVec::new(), @@ -121,9 +121,7 @@ fn get_substructure_equality_expr( span: Span, substructure: Substructure<'_>, ) -> BlockOrExpr { - use SubstructureFields::*; - - BlockOrExpr::new_expr(match substructure.fields { + BlockOrExpr::new_expr(match substructure { EnumMatching(.., fields) | Struct(.., fields) => { let combine = move |acc, field| { let rhs = get_field_equality_expr(cx, field); @@ -172,9 +170,8 @@ fn get_substructure_equality_expr( /// Panics if there are not exactly two arguments to compare (should be `self` /// and `other`). fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> Box { - let [rhs] = &field.other_selflike_exprs[..] else { - cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); - }; + let rhs = + field.other_selflike_expr.as_ref().expect("not exactly 2 arguments in `derive(PartialEq)`"); cx.expr_binary( field.span, diff --git a/compiler/rustc_builtin_macros/src/deriving/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/partial_ord.rs index 8c1d89da6ab30..e176152c507c9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/partial_ord.rs @@ -14,9 +14,8 @@ pub(crate) fn expand_deriving_partial_ord( push: &mut dyn FnMut(Box), is_const: bool, ) { - let ordering_ty = Path(path_std!(cmp::Ordering)); - let ret_ty = - Path(Path::new_(pathvec!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); + let ordering_ty = Path(path_std!(cx, span, cmp::Ordering)); + let ret_ty = Path(new_path(cx, span, pathvec!(option::Option), &[ordering_ty])); // Order in which to perform matching let discr_then_data = if let ItemKind::Enum(_, _, def) = &item.kind { @@ -82,7 +81,7 @@ pub(crate) fn expand_deriving_partial_ord( let trait_def = TraitDef { span, - path: path_std!(cmp::PartialOrd), + path: path_std!(cx, span, cmp::PartialOrd), skip_path_as_bound: false, needs_copy_as_bound_if_packed: true, additional_bounds: smallvec![], @@ -129,10 +128,9 @@ fn cs_partial_cmp( span, substr, |field| { - let [other_expr] = &field.other_selflike_exprs[..] else { - cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(PartialOrd)`"); - }; - let args = thin_vec![field.self_expr.clone(), other_expr.clone()]; + let other_expr = + field.other_selflike_expr.expect("not exactly 2 arguments in `derive(PartialOrd)`"); + let args = thin_vec![field.self_expr, other_expr]; cx.expr_call_global(field.span, partial_cmp_path.clone(), args) }, |span, mut expr1, expr2| { diff --git a/compiler/rustc_hir_analysis/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs index eef26d783e7b7..06e8bc84e4474 100644 --- a/compiler/rustc_hir_analysis/src/variance/solve.rs +++ b/compiler/rustc_hir_analysis/src/variance/solve.rs @@ -5,6 +5,7 @@ //! optimal solution to the constraints. The final variance for each //! inferred is then written into the `variance_map` in the tcx. +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefIdMap; use rustc_middle::ty; use tracing::debug; @@ -43,16 +44,26 @@ struct SolveContext<'a, 'tcx> { pub(crate) fn solve_constraints<'tcx>( constraints_cx: ConstraintContext<'_, 'tcx>, ) -> ty::CrateVariancesMap<'tcx> { - let ConstraintContext { terms_cx, constraints, .. } = constraints_cx; + let ConstraintContext { terms_cx, mut constraints, .. } = constraints_cx; + let mut overridden_inferreds = FxHashSet::default(); let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()]; + // prime the solutions for certain lang items which have hard-coded variance for (id, variances) in &terms_cx.lang_items { let InferredIndex(start) = terms_cx.inferred_starts[id]; for (i, &variance) in variances.iter().enumerate() { solutions[start + i] = variance; + overridden_inferreds.insert(start + i); } } + // ensure the solutions for overridden inferreds are never constrained by anything else + if !overridden_inferreds.is_empty() { + constraints.retain(|Constraint { inferred: InferredIndex(inferred), .. }| { + !overridden_inferreds.contains(inferred) + }); + } + let mut solutions_cx = SolveContext { terms_cx, constraints, solutions }; solutions_cx.solve(); let variances = solutions_cx.create_map(); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 4a494fda7ca80..5c993141faadc 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -385,44 +385,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // Don't infer a closure signature from a goal that names the closure type as this will - // (almost always) lead to occurs check errors later in type checking. - if self.next_trait_solver() - && let Some(inferred_sig) = inferred_sig - { - // In the new solver it is difficult to explicitly normalize the inferred signature as we - // would have to manually handle universes and rewriting bound vars and placeholders back - // and forth. - // - // Instead we take advantage of the fact that we relating an inference variable with an alias - // will only instantiate the variable if the alias is rigid(*not quite). Concretely we: - // - Create some new variable `?sig` - // - Equate `?sig` with the unnormalized signature, e.g. `fn( as Trait>::Assoc)` - // - Depending on whether ` as Trait>::Assoc` is rigid, ambiguous or normalizeable, - // we will either wind up with `?sig= as Trait>::Assoc/?y/ConcreteTy` respectively. - // - // *: In cases where there are ambiguous aliases in the signature that make use of bound vars - // they will wind up present in `?sig` even though they are non-rigid. - // - // This is a bit weird and means we may wind up discarding the goal due to it naming `expected_ty` - // even though the normalized form may not name `expected_ty`. However, this matches the existing - // behaviour of the old solver and would be technically a breaking change to fix. - let generalized_fnptr_sig = self.next_ty_var(span); - let inferred_fnptr_sig = Ty::new_fn_ptr(self.tcx, inferred_sig.sig); - self.demand_eqtype(span, inferred_fnptr_sig, generalized_fnptr_sig); - - let resolved_sig = self.deeply_resolve_ignoring_regions(generalized_fnptr_sig); - - if resolved_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { - expected_sig = Some(ExpectedSig { - cause_span: inferred_sig.cause_span, - sig: resolved_sig.fn_sig(self.tcx), - }); - } - } else { - if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { - expected_sig = inferred_sig; - } + if inferred_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { + expected_sig = inferred_sig; } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8dccead861de7..5520b059f5678 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -21,7 +21,7 @@ use rustc_macros::{ Decodable, Encodable, StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, }; use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; @@ -870,8 +870,8 @@ impl DynCompatibilityViolation { add_self_sugg: add_self_sugg.clone(), make_sized_sugg: make_sized_sugg.clone(), }, - Self::Method(name, MethodViolation::UndispatchableReceiver(Some(span)), _) => { - DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span) + Self::Method(name, MethodViolation::UndispatchableReceiver(Some((span, lt))), _) => { + DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span, *lt) } Self::Method(name, ..) | Self::AssocConst(name, ..) | Self::GenericAssocTy(name, _) => { DynCompatibilityViolationSolution::MoveToAnotherTrait(*name) @@ -909,7 +909,7 @@ pub enum DynCompatibilityViolationSolution { add_self_sugg: (String, Span), make_sized_sugg: (String, Span), }, - ChangeToRefSelf(Symbol, Span), + ChangeToRefSelf(Symbol, Span, Symbol), MoveToAnotherTrait(Symbol), } @@ -922,30 +922,30 @@ impl DynCompatibilityViolationSolution { add_self_sugg, make_sized_sugg, } => { - err.span_suggestion( + err.span_suggestion_verbose( add_self_sugg.1, format!( - "consider turning `{name}` into a method by giving it a `&self` \ - argument, so that it is accessible through the trait object's vtable" + "consider turning `{name}` into a method by giving it a `&self` argument, \ + so that it is accessible through the trait object's vtable", ), add_self_sugg.0, Applicability::MaybeIncorrect, ); - err.span_suggestion( + err.span_suggestion_verbose( make_sized_sugg.1, format!( - "alternatively, consider constraining `{name}` so it is explicitly \ - marked as not applying to trait objects" + "alternatively, consider constraining `{name}` so it is explicitly marked \ + as not applying to trait objects", ), make_sized_sugg.0, Applicability::MaybeIncorrect, ); } - DynCompatibilityViolationSolution::ChangeToRefSelf(name, span) => { - err.span_suggestion( + DynCompatibilityViolationSolution::ChangeToRefSelf(name, span, lt) => { + err.span_suggestion_verbose( span, format!("consider changing method `{name}`'s `self` parameter to be `&self`"), - "&Self", + format!("&{lt}{}self", if lt != sym::empty { " " } else { "" }), Applicability::MachineApplicable, ); } @@ -983,8 +983,11 @@ pub enum MethodViolation { /// e.g., `fn (mut ap: ...)` CVariadic, - /// the method's receiver (`self` argument) can't be dispatched on - UndispatchableReceiver(Option), + /// The method's receiver (`self` argument) can't be dispatched on + /// + /// The `Span` points at the receiver. The `Symbol` is the lifetime's name `'a` when we have + /// Arbitrary Self Types like `self: &'a ()`. + UndispatchableReceiver(Option<(Span, Symbol)>), } /// Reasons an associated const might not be dyn compatible. diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index f2b221c59ee95..e964c09420b0e 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{ TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Unnormalized, Upcast, elaborate, }; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, kw, sym}; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -403,7 +403,7 @@ pub fn dyn_compatibility_violations_for_assoc_item( // Get an accurate span depending on the violation. let span = match (&v, node) { (MethodViolation::ReferencesSelfInput(Some(span)), _) => *span, - (MethodViolation::UndispatchableReceiver(Some(span)), _) => *span, + (MethodViolation::UndispatchableReceiver(Some((span, _))), _) => *span, (MethodViolation::ReferencesImplTraitInTrait(span), _) => *span, (MethodViolation::ReferencesSelfOutput, Some(node)) => { node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) @@ -519,16 +519,40 @@ fn virtual_call_violations_for_method<'tcx>( // `Receiver: Unsize dyn Trait]>`. if receiver_ty != tcx.types.self_param { if !receiver_is_dispatchable(tcx, method, receiver_ty) { - let span = if let Some(hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(sig, _), + let span_n_lt = if let Some(hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, trait_fn), .. })) = tcx.hir_get_if_local(method.def_id).as_ref() { - Some(sig.decl.inputs[0].span) + // If we have `self: &'a Ty`, get `'a`, so that we can suggest `&'a self`. + let lt = match sig.decl.inputs[0].kind { + hir::TyKind::Ref(lt, _) if lt.ident.name == kw::UnderscoreLifetime => { + sym::empty + } + hir::TyKind::Ref(lt, _) => lt.ident.name, + _ => sym::empty, + }; + // Get the `Span` for all of `self: Ty`, not just `Ty`. + match trait_fn { + hir::TraitFn::Required([Some(name), ..]) + if name.span.eq_ctxt(sig.decl.inputs[0].span) => + { + Some(name.span.to(sig.decl.inputs[0].span)) + } + hir::TraitFn::Provided(body_id) + if let body = tcx.hir_body(*body_id) + && let Some(p) = body.params.get(0) + && p.span.eq_ctxt(p.ty_span) => + { + Some(p.span.to(p.ty_span)) + } + _ => None, + } + .map(|sp| (sp, lt)) } else { None }; - errors.push(MethodViolation::UndispatchableReceiver(span)); + errors.push(MethodViolation::UndispatchableReceiver(span_n_lt)); } else { // We confirm that the `receiver_is_dispatchable` is accurate later, // see `check_receiver_correct`. It should be kept in sync with this code. diff --git a/library/core/src/cell/covariant_unsafe_cell.rs b/library/core/src/cell/covariant_unsafe_cell.rs index 3876cc404cd2e..11ac9b58bbb90 100644 --- a/library/core/src/cell/covariant_unsafe_cell.rs +++ b/library/core/src/cell/covariant_unsafe_cell.rs @@ -170,14 +170,3 @@ impl fmt::Debug for CovariantUnsafeCell { f.debug_struct("CovariantUnsafeCell").finish_non_exhaustive() } } - -#[cfg(test)] -mod tests { - use super::*; - - fn _covarience<'short, 'long: 'short>( - x: CovariantUnsafeCell<&'long ()>, - ) -> CovariantUnsafeCell<&'short ()> { - x - } -} diff --git a/tests/ui/derives/deriving-all-codegen.stdout b/tests/ui/derives/deriving-all-codegen.stdout index be6bd1a914c65..ddd1158132c7d 100644 --- a/tests/ui/derives/deriving-all-codegen.stdout +++ b/tests/ui/derives/deriving-all-codegen.stdout @@ -46,7 +46,7 @@ impl ::core::fmt::Debug for Empty { #[automatically_derived] impl ::core::default::Default for Empty { #[inline] - fn default() -> Self { Empty } + fn default() -> Self { Self } } #[automatically_derived] impl ::core::hash::Hash for Empty { @@ -109,7 +109,7 @@ impl ::core::fmt::Debug for Point { impl ::core::default::Default for Point { #[inline] fn default() -> Self { - Point { + Self { x: ::core::default::Default::default(), y: ::core::default::Default::default(), } @@ -193,7 +193,7 @@ impl ::core::fmt::Debug for PackedPoint { impl ::core::default::Default for PackedPoint { #[inline] fn default() -> Self { - PackedPoint { + Self { x: ::core::default::Default::default(), y: ::core::default::Default::default(), } @@ -270,9 +270,7 @@ impl ::core::fmt::Debug for TupleSingleField { #[automatically_derived] impl ::core::default::Default for TupleSingleField { #[inline] - fn default() -> Self { - TupleSingleField(::core::default::Default::default()) - } + fn default() -> Self { Self(::core::default::Default::default()) } } #[automatically_derived] impl ::core::convert::From for TupleSingleField { @@ -345,9 +343,7 @@ impl ::core::fmt::Debug for SingleField { #[automatically_derived] impl ::core::default::Default for SingleField { #[inline] - fn default() -> Self { - SingleField { foo: ::core::default::Default::default() } - } + fn default() -> Self { Self { foo: ::core::default::Default::default() } } } #[automatically_derived] impl ::core::convert::From for SingleField { @@ -435,7 +431,7 @@ impl ::core::fmt::Debug for Big { impl ::core::default::Default for Big { #[inline] fn default() -> Self { - Big { + Self { b1: ::core::default::Default::default(), b2: ::core::default::Default::default(), b3: ::core::default::Default::default(), @@ -626,7 +622,7 @@ struct NonCopy(u32); #[automatically_derived] impl ::core::clone::Clone for NonCopy { #[inline] - fn clone(&self) -> Self { NonCopy(::core::clone::Clone::clone(&self.0)) } + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } } // A packed struct that doesn't impl `Copy`, which means it gets the non-trivial @@ -636,9 +632,7 @@ struct PackedNonCopy(u32); #[automatically_derived] impl ::core::clone::Clone for PackedNonCopy { #[inline] - fn clone(&self) -> Self { - PackedNonCopy(::core::clone::Clone::clone(&{ self.0 })) - } + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&{ self.0 })) } } // A struct that impls `Copy` manually, which means it gets the non-trivial @@ -647,9 +641,7 @@ struct ManualCopy(u32); #[automatically_derived] impl ::core::clone::Clone for ManualCopy { #[inline] - fn clone(&self) -> Self { - ManualCopy(::core::clone::Clone::clone(&self.0)) - } + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } } impl Copy for ManualCopy {} @@ -660,9 +652,7 @@ struct PackedManualCopy(u32); #[automatically_derived] impl ::core::clone::Clone for PackedManualCopy { #[inline] - fn clone(&self) -> Self { - PackedManualCopy(::core::clone::Clone::clone(&{ self.0 })) - } + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&{ self.0 })) } } impl Copy for PackedManualCopy {} @@ -735,7 +725,7 @@ impl ::core::clone::Clone for Generic where T::A: ::core::clone::Clone { #[inline] fn clone(&self) -> Self { - Generic { + Self { t: ::core::clone::Clone::clone(&self.t), ta: ::core::clone::Clone::clone(&self.ta), u: ::core::clone::Clone::clone(&self.u), @@ -761,7 +751,7 @@ impl T::A: ::core::default::Default { #[inline] fn default() -> Self { - Generic { + Self { t: ::core::default::Default::default(), ta: ::core::default::Default::default(), u: ::core::default::Default::default(), @@ -854,7 +844,7 @@ impl Self { - PackedGeneric(::core::clone::Clone::clone(&{ self.0 }), + Self(::core::clone::Clone::clone(&{ self.0 }), ::core::clone::Clone::clone(&{ self.1 }), ::core::clone::Clone::clone(&{ self.2 })) } @@ -881,7 +871,7 @@ impl T::A: ::core::default::Default { #[inline] fn default() -> Self { - PackedGeneric(::core::default::Default::default(), + Self(::core::default::Default::default(), ::core::default::Default::default(), ::core::default::Default::default()) } @@ -1029,7 +1019,7 @@ impl ::core::clone::Clone for Enum1 { fn clone(&self) -> Self { match self { Enum1::Single { x: __self_0 } => - Enum1::Single { x: ::core::clone::Clone::clone(__self_0) }, + Self::Single { x: ::core::clone::Clone::clone(__self_0) }, } } } @@ -1103,7 +1093,7 @@ enum Fieldless1 { #[automatically_derived] impl ::core::clone::Clone for Fieldless1 { #[inline] - fn clone(&self) -> Self { Fieldless1::A } + fn clone(&self) -> Self { Self::A } } #[automatically_derived] impl ::core::fmt::Debug for Fieldless1 { @@ -1428,11 +1418,11 @@ impl ::core::clone::Clone for Fielded { fn clone(&self) -> Self { match self { Fielded::X(__self_0) => - Fielded::X(::core::clone::Clone::clone(__self_0)), + Self::X(::core::clone::Clone::clone(__self_0)), Fielded::Y(__self_0) => - Fielded::Y(::core::clone::Clone::clone(__self_0)), + Self::Y(::core::clone::Clone::clone(__self_0)), Fielded::Z(__self_0) => - Fielded::Z(::core::clone::Clone::clone(__self_0)), + Self::Z(::core::clone::Clone::clone(__self_0)), } } } @@ -1536,9 +1526,9 @@ impl ::core::clone::Clone fn clone(&self) -> Self { match self { EnumGeneric::One(__self_0) => - EnumGeneric::One(::core::clone::Clone::clone(__self_0)), + Self::One(::core::clone::Clone::clone(__self_0)), EnumGeneric::Two(__self_0) => - EnumGeneric::Two(::core::clone::Clone::clone(__self_0)), + Self::Two(::core::clone::Clone::clone(__self_0)), } } } @@ -1746,9 +1736,7 @@ impl ::core::marker::Copy for FooCloneAndCopy { } #[automatically_derived] impl ::core::clone::Clone for FooCloneAndCopy { #[inline] - fn clone(&self) -> Self { - FooCloneAndCopy(::core::clone::Clone::clone(&self.0)) - } + fn clone(&self) -> Self { Self(::core::clone::Clone::clone(&self.0)) } } struct FooPartialOrdOrd(i32); diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr index 867a719e2ebfd..8048ff3e9c0c3 100644 --- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr +++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr @@ -1,38 +1,42 @@ error[E0038]: the trait `Fetcher` is not dyn compatible --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:19:21 | -LL | fn get<'a>(self: &'a Box) -> Pin> + 'a>> - | ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self` -... LL | fn fetcher() -> Box { | ^^^^^^^^^^^ `Fetcher` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 + --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:16 | LL | pub trait Fetcher: Send + Sync { | ------- this trait is not dyn compatible... LL | fn get<'a>(self: &'a Box) -> Pin> + 'a>> - | ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on + | ^^^^^^^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on +help: consider changing method `get`'s `self` parameter to be `&self` + | +LL - fn get<'a>(self: &'a Box) -> Pin> + 'a>> +LL + fn get<'a>(&'a self) -> Pin> + 'a>> + | error[E0038]: the trait `Fetcher` is not dyn compatible --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:25:19 | -LL | fn get<'a>(self: &'a Box) -> Pin> + 'a>> - | ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self` -... LL | let fetcher = fetcher(); | ^^^^^^^^^ `Fetcher` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 + --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:16 | LL | pub trait Fetcher: Send + Sync { | ------- this trait is not dyn compatible... LL | fn get<'a>(self: &'a Box) -> Pin> + 'a>> - | ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on + | ^^^^^^^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on +help: consider changing method `get`'s `self` parameter to be `&self` + | +LL - fn get<'a>(self: &'a Box) -> Pin> + 'a>> +LL + fn get<'a>(&'a self) -> Pin> + 'a>> + | error: aborting due to 2 previous errors diff --git a/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr b/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr index 6ca8ec6bd1a5a..e333fccd69f5d 100644 --- a/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr +++ b/tests/ui/dyn-compatibility/unsafe-binders-bare-trait-object-next-solver.stderr @@ -32,20 +32,22 @@ LL | fn method(self: &unsafe<'ops> &'a dyn Bar) {} error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:17:13 | -LL | fn method(self: &unsafe<'ops> &'a Bar) {} - | --------------------- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self` -... LL | fn test(x: &dyn Foo) { | ^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:21 + --> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:15 | LL | trait Foo: Deref &'a dyn Bar> { | --- this trait is not dyn compatible... LL | fn method(self: &unsafe<'ops> &'a Bar) {} - | ^^^^^^^^^^^^^^^^^^^^^ ...because method `method`'s `self` parameter cannot be dispatched on + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `method`'s `self` parameter cannot be dispatched on +help: consider changing method `method`'s `self` parameter to be `&self` + | +LL - fn method(self: &unsafe<'ops> &'a Bar) {} +LL + fn method(&self) {} + | error[E0599]: no method named `method` found for reference `&dyn Foo` in the current scope --> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:19:7 diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr index c70ab65aa9056..3aeb3edb8690c 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr @@ -1,21 +1,23 @@ error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:33 | -LL | fn ptr(self: Ptr); - | --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self` -... LL | Ptr(Box::new(4)) as Ptr; | ^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18 + --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:12 | LL | trait Trait { | ----- this trait is not dyn compatible... LL | fn ptr(self: Ptr); - | ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on + | ^^^^^^^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on = help: only type `i32` implements `Trait`; consider using it directly instead. +help: consider changing method `ptr`'s `self` parameter to be `&self` + | +LL - fn ptr(self: Ptr); +LL + fn ptr(&self); + | error: aborting due to 1 previous error diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr index fe4802c9b3a47..ccc322d36acea 100644 --- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr +++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr @@ -1,21 +1,23 @@ error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/arbitrary-self-types-dyn-incompatible.rs:29:39 | -LL | fn foo(self: &Rc) -> usize; - | --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self` -... LL | let x = Rc::new(5usize) as Rc; | ^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/arbitrary-self-types-dyn-incompatible.rs:4:18 + --> $DIR/arbitrary-self-types-dyn-incompatible.rs:4:12 | LL | trait Foo { | --- this trait is not dyn compatible... LL | fn foo(self: &Rc) -> usize; - | ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on + | ^^^^^^^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on = help: only type `usize` implements `Foo`; consider using it directly instead. +help: consider changing method `foo`'s `self` parameter to be `&self` + | +LL - fn foo(self: &Rc) -> usize; +LL + fn foo(&self) -> usize; + | error: aborting due to 1 previous error diff --git a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr index b37dd6411cab3..276da3ebaf9bc 100644 --- a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr +++ b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr @@ -1,20 +1,22 @@ error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:12:13 | -LL | fn method(self: &W) {} - | -- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self` -... LL | fn test(x: &dyn Foo) { | ^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21 + --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:15 | LL | trait Foo: Deref { | --- this trait is not dyn compatible... LL | fn method(self: &W) {} - | ^^ ...because method `method`'s `self` parameter cannot be dispatched on + | ^^^^^^^^ ...because method `method`'s `self` parameter cannot be dispatched on +help: consider changing method `method`'s `self` parameter to be `&self` + | +LL - fn method(self: &W) {} +LL + fn method(&self) {} + | error[E0307]: invalid `self` parameter type: `&W` --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21 diff --git a/tests/ui/stats/macro-stats.stderr b/tests/ui/stats/macro-stats.stderr index e3ef2add347dc..95567e20db3bf 100644 --- a/tests/ui/stats/macro-stats.stderr +++ b/tests/ui/stats/macro-stats.stderr @@ -2,11 +2,11 @@ macro-stats ==================================================================== macro-stats MACRO EXPANSION STATS: macro_stats macro-stats Macro Name Uses Lines Avg Lines Bytes Avg Bytes macro-stats ----------------------------------------------------------------------------------- -macro-stats #[derive(Clone)] 8 67 8.4 1_895 236.9 +macro-stats #[derive(Clone)] 8 67 8.4 1_909 238.6 macro-stats #[derive(Hash)] 2 17 8.5 565 282.5 macro-stats q! 1 26 26.0 519 519.0 macro-stats #[derive(Ord)] 1 15 15.0 505 505.0 -macro-stats #[derive(Default)] 2 16 8.0 407 203.5 +macro-stats #[derive(Default)] 2 16 8.0 409 204.5 macro-stats #[derive(Eq)] 1 11 11.0 312 312.0 macro-stats #[derive(Debug)] 1 8 8.0 277 277.0 macro-stats #[derive(PartialEq)] 1 9 9.0 269 269.0 diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed index 2b26d8cc82ee3..3bc052f127214 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed @@ -3,7 +3,7 @@ trait Trait { fn foo(&self) where Self: Other, Self: Sized { } - fn bar(self: &Self) {} //~ ERROR invalid `self` parameter type + fn bar(&self) {} //~ ERROR invalid `self` parameter type } fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` is not dyn compatible diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr index 17c819660f51d..a1d5a3bd2228c 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr @@ -13,7 +13,7 @@ LL | trait Trait { LL | fn foo() where Self: Other, { } | ^^^ ...because associated function `foo` has no `self` parameter LL | fn bar(self: ()) {} - | ^^ ...because method `bar`'s `self` parameter cannot be dispatched on + | ^^^^^^^^ ...because method `bar`'s `self` parameter cannot be dispatched on help: consider turning `foo` into a method by giving it a `&self` argument, so that it is accessible through the trait object's vtable | LL | fn foo(&self) where Self: Other, { } @@ -25,7 +25,7 @@ LL | fn foo() where Self: Other, Self: Sized { } help: consider changing method `bar`'s `self` parameter to be `&self` | LL - fn bar(self: ()) {} -LL + fn bar(self: &Self) {} +LL + fn bar(&self) {} | error[E0307]: invalid `self` parameter type: `()` diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr index f29950de63798..7fb3980839e4f 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr @@ -19,9 +19,6 @@ LL | impl LeakTr for LeakS {} error[E0038]: the trait `DynCompatCheck2` is not dyn compatible --> $DIR/maybe-bounds-in-dyn-traits.rs:90:17 | -LL | fn mut_foo(&mut self) {} - | --------- help: consider changing method `mut_foo`'s `self` parameter to be `&self`: `&Self` -... LL | let _: &dyn DynCompatCheck2 = &NonLeakS; | ^^^^^^^^^^^^^^^ `DynCompatCheck2` is not dyn compatible | @@ -34,6 +31,11 @@ LL | trait DynCompatCheck2: ?Leak { LL | fn mut_foo(&mut self) {} | ^^^^^^^^^ ...because method `mut_foo`'s `self` parameter cannot be dispatched on = help: only type `NonLeakS` implements `DynCompatCheck2`; consider using it directly instead. +help: consider changing method `mut_foo`'s `self` parameter to be `&self` + | +LL - fn mut_foo(&mut self) {} +LL + fn mut_foo(&self) {} + | error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied --> $DIR/maybe-bounds-in-dyn-traits.rs:98:26 diff --git a/tests/ui/variance/covariant_unsafe_cell_is_covariant.rs b/tests/ui/variance/covariant_unsafe_cell_is_covariant.rs new file mode 100644 index 0000000000000..7664e09a851dd --- /dev/null +++ b/tests/ui/variance/covariant_unsafe_cell_is_covariant.rs @@ -0,0 +1,14 @@ +//@ build-pass + +#![feature(covariant_unsafe_cell)] + +use std::cell::CovariantUnsafeCell; + +/// this function compiling ensures that CovariantUnsafeCell is actually covariant +fn _assert_covariance<'short, 'long: 'short>( + x: CovariantUnsafeCell<&'long ()>, +) -> CovariantUnsafeCell<&'short ()> { + x +} + +fn main () {} diff --git a/tests/ui/variance/variance-types.rs b/tests/ui/variance/variance-types.rs index 3b3ac929a2633..f7e8625bce62b 100644 --- a/tests/ui/variance/variance-types.rs +++ b/tests/ui/variance/variance-types.rs @@ -1,5 +1,5 @@ -#![allow(dead_code)] #![feature(rustc_attrs)] +#![feature(covariant_unsafe_cell)] use std::cell::Cell; @@ -38,4 +38,19 @@ enum Enum { //~ ERROR [A: +, B: -, C: o] Zed(Covariant,Contravariant) } +#[rustc_dump_variances] +struct PhantomDataIsCovariant { //~ ERROR [A: +] + t: std::marker::PhantomData +} + +#[rustc_dump_variances] +struct UnsafeCellIsInvariant { //~ ERROR [A: o] + t: std::cell::UnsafeCell +} + +#[rustc_dump_variances] +struct CovariantUnsafeCellIsCovariant { //~ ERROR [A: +] + t: std::cell::CovariantUnsafeCell +} + pub fn main() { } diff --git a/tests/ui/variance/variance-types.stderr b/tests/ui/variance/variance-types.stderr index f2a6794942553..e66f4bacc15e4 100644 --- a/tests/ui/variance/variance-types.stderr +++ b/tests/ui/variance/variance-types.stderr @@ -34,5 +34,23 @@ error: [A: +, B: -, C: o] LL | enum Enum { | ^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: [A: +] + --> $DIR/variance-types.rs:42:1 + | +LL | struct PhantomDataIsCovariant { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: [A: o] + --> $DIR/variance-types.rs:47:1 + | +LL | struct UnsafeCellIsInvariant { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: [A: +] + --> $DIR/variance-types.rs:52:1 + | +LL | struct CovariantUnsafeCellIsCovariant { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors