diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 576e90ae66b76..679dc0866f235 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -442,7 +442,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet { pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) { if let DefKind::AssocFn = tcx.def_kind(id) { let parent_id = tcx.local_parent(id); - if let DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) { + if let DefKind::Trait | DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) { tcx.sess .struct_span_err( attr_span, diff --git a/compiler/rustc_hir_analysis/locales/en-US.ftl b/compiler/rustc_hir_analysis/locales/en-US.ftl index df42881644487..dbe15ed5e9b99 100644 --- a/compiler/rustc_hir_analysis/locales/en-US.ftl +++ b/compiler/rustc_hir_analysis/locales/en-US.ftl @@ -42,6 +42,9 @@ hir_analysis_assoc_type_binding_not_allowed = associated type bindings are not allowed here .label = associated type not allowed here +hir_analysis_parenthesized_fn_trait_expansion = + parenthesized trait syntax expands to `{$expanded_type}` + hir_analysis_typeof_reserved_keyword_used = `typeof` is a reserved keyword but unimplemented .suggestion = consider replacing `typeof(...)` with an actual type diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index c49e4d9d5818e..156334fe785b9 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -1,10 +1,14 @@ use crate::astconv::AstConv; -use crate::errors::{ManualImplementation, MissingTypeParams}; +use crate::errors::{ + AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams, + ParenthesizedFnTraitExpansion, +}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::traits::FulfillmentError; +use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{self, Ty}; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; @@ -78,43 +82,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Do not suggest the other syntax if we are in trait impl: // the desugaring would contain an associated type constraint. if !is_impl { - let args = trait_segment - .args - .as_ref() - .and_then(|args| args.args.get(0)) - .and_then(|arg| match arg { - hir::GenericArg::Type(ty) => match ty.kind { - hir::TyKind::Tup(t) => t - .iter() - .map(|e| sess.source_map().span_to_snippet(e.span)) - .collect::, _>>() - .map(|a| a.join(", ")), - _ => sess.source_map().span_to_snippet(ty.span), - } - .map(|s| format!("({})", s)) - .ok(), - _ => None, - }) - .unwrap_or_else(|| "()".to_string()); - let ret = trait_segment - .args() - .bindings - .iter() - .find_map(|b| match (b.ident.name == sym::Output, &b.kind) { - (true, hir::TypeBindingKind::Equality { term }) => { - let span = match term { - hir::Term::Ty(ty) => ty.span, - hir::Term::Const(c) => self.tcx().hir().span(c.hir_id), - }; - sess.source_map().span_to_snippet(span).ok() - } - _ => None, - }) - .unwrap_or_else(|| "()".to_string()); err.span_suggestion( span, "use parenthetical notation instead", - format!("{}{} -> {}", trait_segment.ident, args, ret), + fn_trait_to_string(self.tcx(), trait_segment, true), Applicability::MaybeIncorrect, ); } @@ -629,3 +600,69 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.emit(); } } + +/// Emits an error regarding forbidden type binding associations +pub fn prohibit_assoc_ty_binding( + tcx: TyCtxt<'_>, + span: Span, + segment: Option<(&hir::PathSegment<'_>, Span)>, +) { + tcx.sess.emit_err(AssocTypeBindingNotAllowed { span, fn_trait_expansion: if let Some((segment, span)) = segment && segment.args().parenthesized { + Some(ParenthesizedFnTraitExpansion { span, expanded_type: fn_trait_to_string(tcx, segment, false) }) + } else { + None + }}); +} + +pub(crate) fn fn_trait_to_string( + tcx: TyCtxt<'_>, + trait_segment: &hir::PathSegment<'_>, + parenthesized: bool, +) -> String { + let args = trait_segment + .args + .as_ref() + .and_then(|args| args.args.get(0)) + .and_then(|arg| match arg { + hir::GenericArg::Type(ty) => match ty.kind { + hir::TyKind::Tup(t) => t + .iter() + .map(|e| tcx.sess.source_map().span_to_snippet(e.span)) + .collect::, _>>() + .map(|a| a.join(", ")), + _ => tcx.sess.source_map().span_to_snippet(ty.span), + } + .map(|s| { + // `s.empty()` checks to see if the type is the unit tuple, if so we don't want a comma + if parenthesized || s.is_empty() { format!("({})", s) } else { format!("({},)", s) } + }) + .ok(), + _ => None, + }) + .unwrap_or_else(|| "()".to_string()); + + let ret = trait_segment + .args() + .bindings + .iter() + .find_map(|b| match (b.ident.name == sym::Output, &b.kind) { + (true, hir::TypeBindingKind::Equality { term }) => { + let span = match term { + hir::Term::Ty(ty) => ty.span, + hir::Term::Const(c) => tcx.hir().span(c.hir_id), + }; + + (span != tcx.hir().span(trait_segment.hir_id)) + .then_some(tcx.sess.source_map().span_to_snippet(span).ok()) + .flatten() + } + _ => None, + }) + .unwrap_or_else(|| "()".to_string()); + + if parenthesized { + format!("{}{} -> {}", trait_segment.ident, args, ret) + } else { + format!("{}<{}, Output={}>", trait_segment.ident, args, ret) + } +} diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 7f6518ffd7148..2f4963f6bc311 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -1,9 +1,8 @@ use super::IsMethodCall; use crate::astconv::{ - CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, - GenericArgCountResult, GenericArgPosition, + errors::prohibit_assoc_ty_binding, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, + GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition, }; -use crate::errors::AssocTypeBindingNotAllowed; use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs}; use rustc_ast::ast::ParamKindOrd; use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; @@ -433,7 +432,7 @@ pub(crate) fn check_generic_arg_count( (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params(); if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() { - prohibit_assoc_ty_binding(tcx, b.span); + prohibit_assoc_ty_binding(tcx, b.span, None); } let explicit_late_bound = @@ -589,11 +588,6 @@ pub(crate) fn check_generic_arg_count( } } -/// Emits an error regarding forbidden type binding associations -pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) { - tcx.sess.emit_err(AssocTypeBindingNotAllowed { span }); -} - /// Prohibits explicit lifetime arguments if late-bound lifetime parameters /// are present. This is used both for datatypes and function calls. pub(crate) fn prohibit_explicit_late_bound_lifetimes( diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 899029d98e0c4..5db404608b36f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -5,9 +5,8 @@ mod errors; pub mod generics; -use crate::astconv::generics::{ - check_generic_arg_count, create_substs_for_generic_args, prohibit_assoc_ty_binding, -}; +use crate::astconv::errors::prohibit_assoc_ty_binding; +use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args}; use crate::bounds::Bounds; use crate::collect::HirPlaceholderCollector; use crate::errors::{ @@ -295,7 +294,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::BoundConstness::NotConst, ); if let Some(b) = item_segment.args().bindings.first() { - prohibit_assoc_ty_binding(self.tcx(), b.span); + prohibit_assoc_ty_binding(self.tcx(), b.span, Some((item_segment, span))); } substs @@ -631,7 +630,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); if let Some(b) = item_segment.args().bindings.first() { - prohibit_assoc_ty_binding(self.tcx(), b.span); + prohibit_assoc_ty_binding(self.tcx(), b.span, Some((item_segment, span))); } args @@ -825,7 +824,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { constness, ); if let Some(b) = trait_segment.args().bindings.first() { - prohibit_assoc_ty_binding(self.tcx(), b.span); + prohibit_assoc_ty_binding(self.tcx(), b.span, Some((trait_segment, span))); } self.tcx().mk_trait_ref(trait_def_id, substs) } @@ -2596,7 +2595,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { for segment in segments { // Only emit the first error to avoid overloading the user with error messages. if let Some(b) = segment.args().bindings.first() { - prohibit_assoc_ty_binding(self.tcx(), b.span); + prohibit_assoc_ty_binding(self.tcx(), b.span, None); return true; } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index dd40706f1d345..8a697b4c51488 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -129,6 +129,18 @@ pub struct AssocTypeBindingNotAllowed { #[primary_span] #[label] pub span: Span, + + #[subdiagnostic] + pub fn_trait_expansion: Option, +} + +#[derive(Subdiagnostic)] +#[help(hir_analysis_parenthesized_fn_trait_expansion)] +pub struct ParenthesizedFnTraitExpansion { + #[primary_span] + pub span: Span, + + pub expanded_type: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index eecded557a5b8..37783bc91bb8c 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -148,10 +148,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_ty, op, ); - self.demand_suptype(expr.span, builtin_return_ty, return_ty); + self.demand_eqtype(expr.span, builtin_return_ty, return_ty); + builtin_return_ty + } else { + return_ty } - - return_ty } } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index a43330e2d4ea5..8ac82653c0ee8 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -411,15 +411,28 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } } - ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var( - CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) }, - t, - ), - - ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var( - CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) }, - t, - ), + ty::Infer(ty::IntVar(vid)) => { + let nt = self.infcx.opportunistic_resolve_int_var(vid); + if nt != t { + return self.fold_ty(nt); + } else { + self.canonicalize_ty_var( + CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) }, + t, + ) + } + } + ty::Infer(ty::FloatVar(vid)) => { + let nt = self.infcx.opportunistic_resolve_float_var(vid); + if nt != t { + return self.fold_ty(nt); + } else { + self.canonicalize_ty_var( + CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) }, + t, + ) + } + } ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("encountered a fresh type during canonicalization") diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 33292e871b11c..a2332797e8680 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -34,7 +34,6 @@ use rustc_hir::def_id::DefId; use rustc_middle::infer::canonical::OriginalQueryValues; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; @@ -119,20 +118,30 @@ impl<'tcx> InferCtxt<'tcx> { self.unify_float_variable(!a_is_expected, v_id, v) } - // All other cases of inference are errors - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b))) + // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm. + ( + ty::Alias(AliasKind::Projection, _), + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), + ) + | ( + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), + ty::Alias(AliasKind::Projection, _), + ) if self.tcx.trait_solver_next() => { + bug!() } - (ty::Alias(AliasKind::Projection, _), _) if self.tcx.trait_solver_next() => { + (_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _) + if self.tcx.trait_solver_next() => + { relation.register_type_equate_obligation(a, b); - Ok(b) - } - (_, ty::Alias(AliasKind::Projection, _)) if self.tcx.trait_solver_next() => { - relation.register_type_equate_obligation(b, a); Ok(a) } + // All other cases of inference are errors + (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { + Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b))) + } + _ => ty::relate::super_relate_tys(relation, a, b), } } @@ -161,9 +170,9 @@ impl<'tcx> InferCtxt<'tcx> { // // This probe is probably not strictly necessary but it seems better to be safe and not accidentally find // ourselves with a check to find bugs being required for code to compile because it made inference progress. - self.probe(|_| { + let compatible_types = self.probe(|_| { if a.ty() == b.ty() { - return; + return Ok(()); } // We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the @@ -173,15 +182,24 @@ impl<'tcx> InferCtxt<'tcx> { (relation.param_env(), a.ty(), b.ty()), &mut OriginalQueryValues::default(), ); - - if let Err(NoSolution) = self.tcx.check_tys_might_be_eq(canonical) { + self.tcx.check_tys_might_be_eq(canonical).map_err(|_| { self.tcx.sess.delay_span_bug( DUMMY_SP, &format!("cannot relate consts of different types (a={:?}, b={:?})", a, b,), - ); - } + ) + }) }); + // If the consts have differing types, just bail with a const error with + // the expected const's type. Specifically, we don't want const infer vars + // to do any type shapeshifting before and after resolution. + if let Err(guar) = compatible_types { + return Ok(self.tcx.const_error_with_guaranteed( + if relation.a_is_expected() { a.ty() } else { b.ty() }, + guar, + )); + } + match (a.kind(), b.kind()) { ( ty::ConstKind::Infer(InferConst::Var(a_vid)), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 4a2a55573131a..4a834957959db 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1363,6 +1363,28 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().const_unification_table().find(var) } + /// Resolves an int var to a rigid int type, if it was constrained to one, + /// or else the root int var in the unification table. + pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { + let mut inner = self.inner.borrow_mut(); + if let Some(value) = inner.int_unification_table().probe_value(vid) { + value.to_type(self.tcx) + } else { + self.tcx.mk_int_var(inner.int_unification_table().find(vid)) + } + } + + /// Resolves a float var to a rigid int type, if it was constrained to one, + /// or else the root float var in the unification table. + pub fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { + let mut inner = self.inner.borrow_mut(); + if let Some(value) = inner.float_unification_table().probe_value(vid) { + value.to_type(self.tcx) + } else { + self.tcx.mk_float_var(inner.float_unification_table().find(vid)) + } + } + /// Where possible, replaces type/const variables in /// `value` with their final value. Note that region variables /// are unaffected. If a type/const variable has not been unified, it diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 8507ca9d89ed7..bb4d91247b81d 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -298,10 +298,10 @@ where } let tail = &tail[first_non_space..]; if let Some(c) = tail.chars().nth(0) { - // For error reporting, we would like the span to contain the character that was not - // skipped. The +1 is necessary to account for the leading \ that started the escape. - let end = start + first_non_space + c.len_utf8() + 1; if c.is_whitespace() { + // For error reporting, we would like the span to contain the character that was not + // skipped. The +1 is necessary to account for the leading \ that started the escape. + let end = start + first_non_space + c.len_utf8() + 1; callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning)); } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 5d0cf23280bc8..42101f6b93152 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -135,6 +135,9 @@ impl<'tcx> Const<'tcx> { _, &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }, )) => { + // Use the type from the param's definition, since we can resolve it, + // not the expected parameter type from WithOptConstParam. + let param_ty = tcx.type_of(def_id).subst_identity(); match tcx.named_bound_var(expr.hir_id) { Some(rbv::ResolvedArg::EarlyBound(_)) => { // Find the name and index of the const parameter by indexing the generics of @@ -143,14 +146,14 @@ impl<'tcx> Const<'tcx> { let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.item_name(def_id); - Some(tcx.mk_const(ty::ParamConst::new(index, name), ty)) + Some(tcx.mk_const(ty::ParamConst::new(index, name), param_ty)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => Some(tcx.mk_const( ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)), - ty, + param_ty, )), Some(rbv::ResolvedArg::Error(guar)) => { - Some(tcx.const_error_with_guaranteed(ty, guar)) + Some(tcx.const_error_with_guaranteed(param_ty, guar)) } arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8cc8a0573bb0f..d9bfacd6e3cf3 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -995,7 +995,7 @@ impl<'tcx> Term<'tcx> { pub fn is_infer(&self) -> bool { match self.unpack() { - TermKind::Ty(ty) => ty.is_ty_or_numeric_infer(), + TermKind::Ty(ty) => ty.is_ty_var(), TermKind::Const(ct) => ct.is_ct_infer(), } } diff --git a/compiler/rustc_parse/locales/en-US.ftl b/compiler/rustc_parse/locales/en-US.ftl index 5c7dc1e2abf91..ab7931d74d766 100644 --- a/compiler/rustc_parse/locales/en-US.ftl +++ b/compiler/rustc_parse/locales/en-US.ftl @@ -709,7 +709,7 @@ parse_zero_chars = empty character literal parse_lone_slash = invalid trailing slash in literal .label = {parse_lone_slash} -parse_unskipped_whitespace = non-ASCII whitespace symbol '{$ch}' is not skipped +parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped .label = {parse_unskipped_whitespace} parse_multiple_skipped_lines = multiple lines skipped by escaped newline diff --git a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs index 981a8f45e4542..7ee4f33230630 100644 --- a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs @@ -278,16 +278,16 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), } } - ty::Infer(ty::IntVar(_)) => { - let nt = self.infcx.shallow_resolve(t); + ty::Infer(ty::IntVar(vid)) => { + let nt = self.infcx.opportunistic_resolve_int_var(vid); if nt != t { return self.fold_ty(nt); } else { CanonicalVarKind::Ty(CanonicalTyVarKind::Int) } } - ty::Infer(ty::FloatVar(_)) => { - let nt = self.infcx.shallow_resolve(t); + ty::Infer(ty::FloatVar(vid)) => { + let nt = self.infcx.opportunistic_resolve_float_var(vid); if nt != t { return self.fold_ty(nt); } else { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 21c158fd0fddd..ee41d840bae92 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -601,10 +601,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, "confirm_fn_pointer_candidate"); let tcx = self.tcx(); - let self_ty = self + + let Some(self_ty) = self .infcx - .shallow_resolve(obligation.self_ty().no_bound_vars()) - .expect("fn pointer should not capture bound vars from predicate"); + .shallow_resolve(obligation.self_ty().no_bound_vars()) else + { + // FIXME: Ideally we'd support `for<'a> fn(&'a ()): Fn(&'a ())`, + // but we do not currently. Luckily, such a bound is not + // particularly useful, so we don't expect users to write + // them often. + return Err(SelectionError::Unimplemented); + }; + let sig = self_ty.fn_sig(tcx); let trait_ref = closure_trait_ref_and_return_type( tcx, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 48c3b3601b4d3..ba4df2b3720ef 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -465,14 +465,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if candidates.len() > 1 { let mut i = 0; while i < candidates.len() { - let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { + let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| { self.candidate_should_be_dropped_in_favor_of( &candidates[i], &candidates[j], needs_infer, - ) + ) == DropVictim::Yes }); - if is_dup { + if should_drop_i { debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); candidates.swap_remove(i); } else { @@ -1842,16 +1842,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ProjectionMatchesProjection::No } } +} - /////////////////////////////////////////////////////////////////////////// - // WINNOW - // - // Winnowing is the process of attempting to resolve ambiguity by - // probing further. During the winnowing process, we unify all - // type variables and then we also attempt to evaluate recursive - // bounds to see if they are satisfied. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum DropVictim { + Yes, + No, +} - /// Returns `true` if `victim` should be dropped in favor of +/// ## Winnowing +/// +/// Winnowing is the process of attempting to resolve ambiguity by +/// probing further. During the winnowing process, we unify all +/// type variables and then we also attempt to evaluate recursive +/// bounds to see if they are satisfied. +impl<'tcx> SelectionContext<'_, 'tcx> { + /// Returns `DropVictim::Yes` if `victim` should be dropped in favor of /// `other`. Generally speaking we will drop duplicate /// candidates and prefer where-clause candidates. /// @@ -1861,9 +1867,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { victim: &EvaluatedCandidate<'tcx>, other: &EvaluatedCandidate<'tcx>, needs_infer: bool, - ) -> bool { + ) -> DropVictim { if victim.candidate == other.candidate { - return true; + return DropVictim::Yes; } // Check if a bound would previously have been removed when normalizing @@ -1887,11 +1893,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // FIXME(@jswrenn): this should probably be more sophisticated - (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false, + (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No, // (*) - (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => true, - (_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => false, + (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => { + DropVictim::Yes + } + (_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => { + DropVictim::No + } (ParamCandidate(other), ParamCandidate(victim)) => { let same_except_bound_vars = other.skip_binder().trait_ref @@ -1905,28 +1915,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // or the current one if tied (they should both evaluate to the same answer). This is // probably best characterized as a "hack", since we might prefer to just do our // best to *not* create essentially duplicate candidates in the first place. - other.bound_vars().len() <= victim.bound_vars().len() + if other.bound_vars().len() <= victim.bound_vars().len() { + DropVictim::Yes + } else { + DropVictim::No + } } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref && victim.skip_binder().constness == ty::BoundConstness::NotConst && other.skip_binder().polarity == victim.skip_binder().polarity { // Drop otherwise equivalent non-const candidates in favor of const candidates. - true + DropVictim::Yes } else { - false + DropVictim::No } } // Drop otherwise equivalent non-const fn pointer candidates - (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true, + (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes, - // Global bounds from the where clause should be ignored - // here (see issue #50825). Otherwise, we have a where - // clause so don't go around looking for impls. - // Arbitrarily give param candidates priority - // over projection and object candidates. ( - ParamCandidate(ref cand), + ParamCandidate(ref other_cand), ImplCandidate(..) | ClosureCandidate { .. } | GeneratorCandidate @@ -1939,11 +1948,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitAliasCandidate | ObjectCandidate(_) | ProjectionCandidate(..), - ) => !is_global(cand), - (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref cand)) => { + ) => { + if is_global(other_cand) { + DropVictim::No + } else { + // We have a where clause so don't go around looking + // for impls. Arbitrarily give param candidates priority + // over projection and object candidates. + // + // Global bounds from the where clause should be ignored + // here (see issue #50825). + DropVictim::Yes + } + } + (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => { // Prefer these to a global where-clause bound // (see issue #50825). - is_global(cand) + if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No } } ( ImplCandidate(_) @@ -1956,18 +1977,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { has_nested: true } | TraitAliasCandidate, - ParamCandidate(ref cand), + ParamCandidate(ref victim_cand), ) => { // Prefer these to a global where-clause bound // (see issue #50825). - is_global(cand) && other.evaluation.must_apply_modulo_regions() + if is_global(victim_cand) && other.evaluation.must_apply_modulo_regions() { + DropVictim::Yes + } else { + DropVictim::No + } } (ProjectionCandidate(i, _), ProjectionCandidate(j, _)) | (ObjectCandidate(i), ObjectCandidate(j)) => { // Arbitrarily pick the lower numbered candidate for backwards // compatibility reasons. Don't let this affect inference. - i < j && !needs_infer + if i < j && !needs_infer { DropVictim::Yes } else { DropVictim::No } } (ObjectCandidate(_), ProjectionCandidate(..)) | (ProjectionCandidate(..), ObjectCandidate(_)) => { @@ -1987,7 +2012,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { .. } | TraitAliasCandidate, - ) => true, + ) => DropVictim::Yes, ( ImplCandidate(..) @@ -2001,7 +2026,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | BuiltinCandidate { .. } | TraitAliasCandidate, ObjectCandidate(_) | ProjectionCandidate(..), - ) => false, + ) => DropVictim::No, (&ImplCandidate(other_def), &ImplCandidate(victim_def)) => { // See if we can toss out `victim` based on specialization. @@ -2014,7 +2039,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); if other.evaluation.must_apply_modulo_regions() { if tcx.specializes((other_def, victim_def)) { - return true; + return DropVictim::Yes; } } @@ -2060,13 +2085,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // will then correctly report an inference error, since the // existence of multiple marker trait impls tells us nothing // about which one should actually apply. - !needs_infer + if needs_infer { DropVictim::No } else { DropVictim::Yes } } - Some(_) => true, - None => false, + Some(_) => DropVictim::Yes, + None => DropVictim::No, } } else { - false + DropVictim::No } } @@ -2092,10 +2117,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { has_nested: true } | TraitAliasCandidate, - ) => false, + ) => DropVictim::No, } } +} +impl<'tcx> SelectionContext<'_, 'tcx> { fn sized_conditions( &mut self, obligation: &TraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index d1d6a7a90cf74..fcfb60b26030f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -99,10 +99,10 @@ pub fn translate_substs<'tcx>( } fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else( - |_| { + |()| { bug!( - "When translating substitutions for specialization, the expected \ - specialization failed to hold" + "When translating substitutions from {source_impl:?} to {target_impl:?}, \ + the expected specialization failed to hold" ) }, ) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 897d03595d748..9d1720acf3663 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -209,6 +209,12 @@ pub use once::OnceCell; /// A mutable memory location. /// +/// # Memory layout +/// +/// `Cell` has the same [memory layout and caveats as +/// `UnsafeCell`](UnsafeCell#memory-layout). In particular, this means that +/// `Cell` has the same in-memory representation as its inner type `T`. +/// /// # Examples /// /// In this example, you can see that `Cell` enables mutation inside an diff --git a/tests/ui/const-generics/type_mismatch.rs b/tests/ui/const-generics/type_mismatch.rs index 4a7534e371381..daa13277be0a0 100644 --- a/tests/ui/const-generics/type_mismatch.rs +++ b/tests/ui/const-generics/type_mismatch.rs @@ -1,5 +1,6 @@ fn foo() -> [u8; N] { bar::() //~ ERROR mismatched types + //~^ ERROR the constant `N` is not of type `u8` } fn bar() -> [u8; N] {} diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr index b28ae8f7e7101..6d8955e411ec3 100644 --- a/tests/ui/const-generics/type_mismatch.stderr +++ b/tests/ui/const-generics/type_mismatch.stderr @@ -1,3 +1,15 @@ +error: the constant `N` is not of type `u8` + --> $DIR/type_mismatch.rs:2:5 + | +LL | bar::() + | ^^^^^^^^ + | +note: required by a bound in `bar` + --> $DIR/type_mismatch.rs:6:8 + | +LL | fn bar() -> [u8; N] {} + | ^^^^^^^^^^^ required by this bound in `bar` + error[E0308]: mismatched types --> $DIR/type_mismatch.rs:2:11 | @@ -5,7 +17,7 @@ LL | bar::() | ^ expected `u8`, found `usize` error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:5:26 + --> $DIR/type_mismatch.rs:6:26 | LL | fn bar() -> [u8; N] {} | --- ^^^^^^^ expected `[u8; N]`, found `()` @@ -13,11 +25,11 @@ LL | fn bar() -> [u8; N] {} | implicitly returns `()` as its body has no tail or `return` expression error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:5:31 + --> $DIR/type_mismatch.rs:6:31 | LL | fn bar() -> [u8; N] {} | ^ expected `usize`, found `u8` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/type_not_in_scope.rs b/tests/ui/const-generics/type_not_in_scope.rs index 5933701808b3e..917abaed15e06 100644 --- a/tests/ui/const-generics/type_not_in_scope.rs +++ b/tests/ui/const-generics/type_not_in_scope.rs @@ -6,6 +6,5 @@ impl X { } fn getn() -> [u8; N] {} //~^ ERROR expected type, found built-in attribute `cfg_attr` -//~| ERROR mismatched types fn main() {} diff --git a/tests/ui/const-generics/type_not_in_scope.stderr b/tests/ui/const-generics/type_not_in_scope.stderr index 5f45550a62796..5eb81ca052241 100644 --- a/tests/ui/const-generics/type_not_in_scope.stderr +++ b/tests/ui/const-generics/type_not_in_scope.stderr @@ -10,15 +10,7 @@ error[E0573]: expected type, found built-in attribute `cfg_attr` LL | fn getn() -> [u8; N] {} | ^^^^^^^^ not a type -error[E0308]: mismatched types - --> $DIR/type_not_in_scope.rs:7:33 - | -LL | fn getn() -> [u8; N] {} - | ---- ^^^^^^^ expected `[u8; N]`, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0308, E0412, E0573. -For more information about an error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0412, E0573. +For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index f647380ef9bc4..b1613f638d301 100644 --- a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -64,6 +64,12 @@ error[E0229]: associated type bindings are not allowed here | LL | impl FnOnce() for Foo1 { | ^^^^^^^^ associated type not allowed here + | +help: parenthesized trait syntax expands to `FnOnce<(), Output=()>` + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6 + | +LL | impl FnOnce() for Foo1 { + | ^^^^^^^^ error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6 diff --git a/tests/ui/fn/issue-39259.rs b/tests/ui/fn/issue-39259.rs new file mode 100644 index 0000000000000..5872f1007b015 --- /dev/null +++ b/tests/ui/fn/issue-39259.rs @@ -0,0 +1,13 @@ +#![feature(fn_traits)] +#![feature(unboxed_closures)] + +struct S; + +impl Fn(u32) -> u32 for S { +//~^ ERROR associated type bindings are not allowed here [E0229] + fn call(&self) -> u32 { + 5 + } +} + +fn main() {} diff --git a/tests/ui/fn/issue-39259.stderr b/tests/ui/fn/issue-39259.stderr new file mode 100644 index 0000000000000..b656b76bfe4eb --- /dev/null +++ b/tests/ui/fn/issue-39259.stderr @@ -0,0 +1,15 @@ +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-39259.rs:6:17 + | +LL | impl Fn(u32) -> u32 for S { + | ^^^ associated type not allowed here + | +help: parenthesized trait syntax expands to `Fn<(u32,), Output=u32>` + --> $DIR/issue-39259.rs:6:6 + | +LL | impl Fn(u32) -> u32 for S { + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0229`. diff --git a/tests/ui/higher-rank-trait-bounds/fn-ptr.classic.stderr b/tests/ui/higher-rank-trait-bounds/fn-ptr.classic.stderr new file mode 100644 index 0000000000000..9af6bc45c7a06 --- /dev/null +++ b/tests/ui/higher-rank-trait-bounds/fn-ptr.classic.stderr @@ -0,0 +1,19 @@ +error[E0277]: expected a `Fn<(&'w (),)>` closure, found `fn(&'w ())` + --> $DIR/fn-ptr.rs:12:5 + | +LL | ice(); + | ^^^ expected an `Fn<(&'w (),)>` closure, found `fn(&'w ())` + | + = help: the trait `for<'w> Fn<(&'w (),)>` is not implemented for `fn(&'w ())` +note: required by a bound in `ice` + --> $DIR/fn-ptr.rs:7:25 + | +LL | fn ice() + | --- required by a bound in this function +LL | where +LL | for<'w> fn(&'w ()): Fn(&'w ()), + | ^^^^^^^^^^ required by this bound in `ice` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-rank-trait-bounds/fn-ptr.rs b/tests/ui/higher-rank-trait-bounds/fn-ptr.rs new file mode 100644 index 0000000000000..853160f961245 --- /dev/null +++ b/tests/ui/higher-rank-trait-bounds/fn-ptr.rs @@ -0,0 +1,14 @@ +// revisions: classic next +//[next] compile-flags: -Ztrait-solver=next +//[next] check-pass + +fn ice() +where + for<'w> fn(&'w ()): Fn(&'w ()), +{ +} + +fn main() { + ice(); + //[classic]~^ ERROR expected a `Fn<(&'w (),)>` closure, found `fn(&'w ())` +} diff --git a/tests/ui/issues/issue-66667-function-cmp-cycle.rs b/tests/ui/issues/issue-66667-function-cmp-cycle.rs index 7b025be11a09e..b4f09fbbb04d0 100644 --- a/tests/ui/issues/issue-66667-function-cmp-cycle.rs +++ b/tests/ui/issues/issue-66667-function-cmp-cycle.rs @@ -1,16 +1,19 @@ fn first() { second == 1 //~ ERROR binary operation //~^ ERROR mismatched types + //~| ERROR mismatched types } fn second() { first == 1 //~ ERROR binary operation //~^ ERROR mismatched types + //~| ERROR mismatched types } fn bar() { bar == 1 //~ ERROR binary operation //~^ ERROR mismatched types + //~| ERROR mismatched types } fn main() {} diff --git a/tests/ui/issues/issue-66667-function-cmp-cycle.stderr b/tests/ui/issues/issue-66667-function-cmp-cycle.stderr index 887699ef5ce85..d9a960ce19730 100644 --- a/tests/ui/issues/issue-66667-function-cmp-cycle.stderr +++ b/tests/ui/issues/issue-66667-function-cmp-cycle.stderr @@ -15,8 +15,16 @@ LL | second == 1 = note: expected fn item `fn() {second}` found type `{integer}` +error[E0308]: mismatched types + --> $DIR/issue-66667-function-cmp-cycle.rs:2:5 + | +LL | fn first() { + | - help: try adding a return type: `-> bool` +LL | second == 1 + | ^^^^^^^^^^^ expected `()`, found `bool` + error[E0369]: binary operation `==` cannot be applied to type `fn() {first}` - --> $DIR/issue-66667-function-cmp-cycle.rs:7:11 + --> $DIR/issue-66667-function-cmp-cycle.rs:8:11 | LL | first == 1 | ----- ^^ - {integer} @@ -24,7 +32,7 @@ LL | first == 1 | fn() {first} error[E0308]: mismatched types - --> $DIR/issue-66667-function-cmp-cycle.rs:7:14 + --> $DIR/issue-66667-function-cmp-cycle.rs:8:14 | LL | first == 1 | ^ expected fn item, found integer @@ -32,8 +40,16 @@ LL | first == 1 = note: expected fn item `fn() {first}` found type `{integer}` +error[E0308]: mismatched types + --> $DIR/issue-66667-function-cmp-cycle.rs:8:5 + | +LL | fn second() { + | - help: try adding a return type: `-> bool` +LL | first == 1 + | ^^^^^^^^^^ expected `()`, found `bool` + error[E0369]: binary operation `==` cannot be applied to type `fn() {bar}` - --> $DIR/issue-66667-function-cmp-cycle.rs:12:9 + --> $DIR/issue-66667-function-cmp-cycle.rs:14:9 | LL | bar == 1 | --- ^^ - {integer} @@ -41,7 +57,7 @@ LL | bar == 1 | fn() {bar} error[E0308]: mismatched types - --> $DIR/issue-66667-function-cmp-cycle.rs:12:12 + --> $DIR/issue-66667-function-cmp-cycle.rs:14:12 | LL | bar == 1 | ^ expected fn item, found integer @@ -49,7 +65,15 @@ LL | bar == 1 = note: expected fn item `fn() {bar}` found type `{integer}` -error: aborting due to 6 previous errors +error[E0308]: mismatched types + --> $DIR/issue-66667-function-cmp-cycle.rs:14:5 + | +LL | fn bar() { + | - help: try adding a return type: `-> bool` +LL | bar == 1 + | ^^^^^^^^ expected `()`, found `bool` + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/lifetimes/issue-95023.stderr b/tests/ui/lifetimes/issue-95023.stderr index 35c3797c77a85..5b93eff86142d 100644 --- a/tests/ui/lifetimes/issue-95023.stderr +++ b/tests/ui/lifetimes/issue-95023.stderr @@ -25,6 +25,12 @@ error[E0229]: associated type bindings are not allowed here | LL | impl Fn(&isize) for Error { | ^^^^^^^^^^ associated type not allowed here + | +help: parenthesized trait syntax expands to `Fn<(&isize,), Output=()>` + --> $DIR/issue-95023.rs:3:6 + | +LL | impl Fn(&isize) for Error { + | ^^^^^^^^^^ error[E0220]: associated type `B` not found for `Self` --> $DIR/issue-95023.rs:6:44 diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs index 7314fa8cced2a..9108f27b5f7f8 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs @@ -18,4 +18,10 @@ impl Foo for Bar { unsafe fn unsf_foo(&self) {} } +trait Qux { + #[target_feature(enable = "sse2")] + //~^ ERROR cannot be applied to safe trait method + fn foo(&self) {} +} + fn main() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr index 07d6e09005906..eb0f18edd3401 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr @@ -1,3 +1,12 @@ +error: `#[target_feature(..)]` cannot be applied to safe trait method + --> $DIR/trait-impl.rs:22:5 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method +LL | +LL | fn foo(&self) {} + | ------------- not an `unsafe` function + error: `#[target_feature(..)]` cannot be applied to safe trait method --> $DIR/trait-impl.rs:13:5 | @@ -7,5 +16,5 @@ LL | LL | fn foo(&self) {} | ------------- not an `unsafe` function -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs new file mode 100644 index 0000000000000..582b480aa25be --- /dev/null +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs @@ -0,0 +1,12 @@ +#![feature(min_specialization)] + +// An impl that has an erroneous const substitution should not specialize one +// that is well-formed. + +struct S; + +impl Copy for S {} +impl Copy for S {} +//~^ ERROR conflicting implementations of trait `Copy` for type `S<_>` + +fn main() {} diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr new file mode 100644 index 0000000000000..a3906a9a22fec --- /dev/null +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `Copy` for type `S<_>` + --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1 + | +LL | impl Copy for S {} + | -------------------------------- first implementation here +LL | impl Copy for S {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/str/str-escape.rs b/tests/ui/str/str-escape.rs index 0264632fd24a1..10a72421f24a7 100644 --- a/tests/ui/str/str-escape.rs +++ b/tests/ui/str/str-escape.rs @@ -1,11 +1,31 @@ // check-pass +// ignore-tidy-tab + fn main() { let s = "\ "; //~^^^ WARNING multiple lines skipped by escaped newline + assert_eq!(s, ""); + let s = "foo\   bar "; - //~^^^ WARNING non-ASCII whitespace symbol '\u{a0}' is not skipped + //~^^^ WARNING whitespace symbol '\u{a0}' is not skipped + assert_eq!(s, "foo  bar\n "); + + let s = "a\ + b"; + assert_eq!(s, "ab"); + + let s = "a\ + b"; + assert_eq!(s, "ab"); + + let s = "a\ + b"; + //~^^ WARNING whitespace symbol '\u{c}' is not skipped + // '\x0c' is ASCII whitespace, but it may not need skipped + // discussion: https://github.com/rust-lang/rust/pull/108403 + assert_eq!(s, "a\x0cb"); } diff --git a/tests/ui/str/str-escape.stderr b/tests/ui/str/str-escape.stderr index b2501f1a2145f..43b4f7e36f6ab 100644 --- a/tests/ui/str/str-escape.stderr +++ b/tests/ui/str/str-escape.stderr @@ -1,5 +1,5 @@ warning: multiple lines skipped by escaped newline - --> $DIR/str-escape.rs:3:14 + --> $DIR/str-escape.rs:5:14 | LL | let s = "\ | ______________^ @@ -7,15 +7,25 @@ LL | | LL | | "; | |_____________^ skipping everything up to and including this point -warning: non-ASCII whitespace symbol '\u{a0}' is not skipped - --> $DIR/str-escape.rs:7:17 +warning: whitespace symbol '\u{a0}' is not skipped + --> $DIR/str-escape.rs:11:17 | LL | let s = "foo\ | _________________^ LL | |   bar - | | ^ non-ASCII whitespace symbol '\u{a0}' is not skipped + | | ^ whitespace symbol '\u{a0}' is not skipped | |___| | -warning: 2 warnings emitted +warning: whitespace symbol '\u{c}' is not skipped + --> $DIR/str-escape.rs:25:15 + | +LL | let s = "a\ + | _______________^ +LL | | b"; + | | ^- whitespace symbol '\u{c}' is not skipped + | |____| + | + +warning: 3 warnings emitted diff --git a/tests/ui/traits/issue-87558.stderr b/tests/ui/traits/issue-87558.stderr index 494274d8c3075..b647f9794bd95 100644 --- a/tests/ui/traits/issue-87558.stderr +++ b/tests/ui/traits/issue-87558.stderr @@ -17,6 +17,12 @@ error[E0229]: associated type bindings are not allowed here | LL | impl Fn(&isize) for Error { | ^^^^^^^^^^ associated type not allowed here + | +help: parenthesized trait syntax expands to `Fn<(&isize,), Output=()>` + --> $DIR/issue-87558.rs:3:6 + | +LL | impl Fn(&isize) for Error { + | ^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs b/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs new file mode 100644 index 0000000000000..3f7316a2279d3 --- /dev/null +++ b/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs @@ -0,0 +1,21 @@ +// check-pass + +trait Mirror { + type Assoc; +} + +impl Mirror for T { + type Assoc = T; +} + +trait Test {} +impl Test for i64 {} +impl Test for u64 {} + +fn mirror_me(t: T, s: ::Assoc) where ::Assoc: Test {} + +fn main() { + let mut x = 0; + mirror_me(x, 1); + x = 1i64; +} diff --git a/tests/ui/traits/new-solver/int-var-alias-eq.rs b/tests/ui/traits/new-solver/int-var-alias-eq.rs new file mode 100644 index 0000000000000..2da387db4a99f --- /dev/null +++ b/tests/ui/traits/new-solver/int-var-alias-eq.rs @@ -0,0 +1,18 @@ +// check-pass +// compile-flags: -Ztrait-solver=next + +// HIR typeck ends up equating `<_#0i as Add>::Output == _#0i`. +// Want to make sure that we emit an alias-eq goal for this, +// instead of treating it as a type error and bailing. + +fn test() { + // fallback + let x = 1 + 2; +} + +fn test2() -> u32 { + // expectation from return ty + 1 + 2 +} + +fn main() {} diff --git a/tests/ui/transmutability/issue-101739-1.rs b/tests/ui/transmutability/issue-101739-1.rs index bcb8b158edfc5..2b966609108bf 100644 --- a/tests/ui/transmutability/issue-101739-1.rs +++ b/tests/ui/transmutability/issue-101739-1.rs @@ -6,7 +6,7 @@ mod assert { pub fn is_transmutable() where Dst: BikeshedIntrinsicFrom, //~ ERROR cannot find type `Dst` in this scope - //~^ ERROR mismatched types + //~^ the constant `ASSUME_ALIGNMENT` is not of type `Assume` { } } diff --git a/tests/ui/transmutability/issue-101739-1.stderr b/tests/ui/transmutability/issue-101739-1.stderr index 7c6b533ef5f71..f0fa93722b89b 100644 --- a/tests/ui/transmutability/issue-101739-1.stderr +++ b/tests/ui/transmutability/issue-101739-1.stderr @@ -4,13 +4,15 @@ error[E0412]: cannot find type `Dst` in this scope LL | Dst: BikeshedIntrinsicFrom, | ^^^ not found in this scope -error[E0308]: mismatched types - --> $DIR/issue-101739-1.rs:8:50 +error: the constant `ASSUME_ALIGNMENT` is not of type `Assume` + --> $DIR/issue-101739-1.rs:8:14 | LL | Dst: BikeshedIntrinsicFrom, - | ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `BikeshedIntrinsicFrom` + --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL error: aborting due to 2 previous errors -Some errors have detailed explanations: E0308, E0412. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.rs b/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.rs index 5ff567cd07c50..3b261062f782e 100644 --- a/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.rs +++ b/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.rs @@ -1,5 +1,5 @@ // compile-flags: -Ztrait-solver=next -// known-bug: unknown +// check-pass fn main() { (0u8 + 0u8) as char; diff --git a/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.stderr b/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.stderr deleted file mode 100644 index 6b09ccd52140d..0000000000000 --- a/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0271]: type mismatch resolving `char == ::Output` - --> $DIR/cast-checks-handling-projections.rs:5:5 - | -LL | (0u8 + 0u8) as char; - | ^^^^^^^^^^^ types differ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/triagebot.toml b/triagebot.toml index e39a0b06b974e..0388ce9fc9852 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -430,7 +430,7 @@ message = "The Miri subtree was changed" cc = ["@rust-lang/miri"] [mentions."src/tools/rust-analyzer"] -cc = ["@rust-lang/wg-rls-2"] +cc = ["@rust-lang/rust-analyzer"] [mentions."src/tools/rustfmt"] cc = ["@rust-lang/rustfmt"]