diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 1b99f54719fb4..2a03a840eb1aa 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -449,9 +449,16 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // all. That said, we have to allow calling functions inside a `const trait`. These // *are* const-checked! if !ecx.tcx.is_const_fn(def) || find_attr!(ecx.tcx, def, RustcDoNotConstCheck) { - // We certainly do *not* want to actually call the fn - // though, so be sure we return here. - throw_unsup_format!("calling non-const function `{}`", instance) + // We certainly do *not* want to actually call this fn. const-checking should have + // prevented this, but this can be reached with unleashed-miri, so make testing + // simpler by avoiding ICEs there. (Technically this can still ICE if miri-unleash + // was set in a dependency rather than the current crate. That's okay, it's an + // internal unstable feature.) + if ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { + throw_unsup_format!("calling non-const function `{}`", instance) + } else { + span_bug!(ecx.cur_span(), "calling non-const function `{}`", instance) + } } } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 15a435357544d..6e8d490ce0ea4 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -45,6 +45,7 @@ pub struct AnnotateSnippetEmitter { track_diagnostics: bool, terminal_url: TerminalUrl, theme: OutputTheme, + show_suggestions_with_unavailable_source: bool, } impl Debug for AnnotateSnippetEmitter { @@ -60,6 +61,7 @@ impl Debug for AnnotateSnippetEmitter { track_diagnostics, terminal_url, theme, + show_suggestions_with_unavailable_source, } = self; f.debug_struct("AnnotateSnippetEmitter") @@ -73,6 +75,10 @@ impl Debug for AnnotateSnippetEmitter { .field("track_diagnostics", track_diagnostics) .field("terminal_url", terminal_url) .field("theme", theme) + .field( + "show_suggestions_with_unavailable_source", + show_suggestions_with_unavailable_source, + ) .finish() } } @@ -153,6 +159,7 @@ impl AnnotateSnippetEmitter { track_diagnostics: false, terminal_url: TerminalUrl::No, theme: OutputTheme::Ascii, + show_suggestions_with_unavailable_source: false, } } @@ -319,6 +326,12 @@ impl AnnotateSnippetEmitter { SuggestionStyle::HideCodeInline | SuggestionStyle::ShowCode | SuggestionStyle::ShowAlways => { + // Get the original unavailable spans before `suggestion` is consumed. + let unavailable_source_span = if self.show_suggestions_with_unavailable_source { + self.suggestion_span_with_unavailable_source(sm, &suggestion) + } else { + None + }; let substitutions = suggestion .substitutions .into_iter() @@ -368,6 +381,30 @@ impl AnnotateSnippetEmitter { .collect::>(); if substitutions.is_empty() { + if let Some(span) = unavailable_source_span { + let msg = format_diag_message(&suggestion.msg, args).to_string(); + report.push(std::mem::replace( + &mut group, + Group::with_title( + annotate_snippets::Level::HELP.secondary_title(msg), + ), + )); + + let file_ann = collect_annotations(args, &span, sm); + let level = annotate_snippets::Level::HELP; + for (file_idx, (file, annotations)) in file_ann.into_iter().enumerate() + { + group = self.unannotated_messages( + annotations, + &file.name, + sm, + file_idx, + &mut report, + group, + &level, + ); + } + } continue; } let mut msg = format_diag_message(&suggestion.msg, args).to_string(); @@ -652,6 +689,34 @@ impl AnnotateSnippetEmitter { } group } + + fn suggestion_span_with_unavailable_source( + &self, + sm: &Arc, + suggestion: &CodeSuggestion, + ) -> Option { + // These spans cannot be rendered as source patches because their source + // files are unavailable, but can still be shown as locations. + let spans = suggestion + .substitutions + .iter() + .flat_map(|subst| &subst.parts) + .filter_map(|part| { + if sm.is_valid_span(part.span).is_err() { + debug!("suggestion contains an invalid span: {:?}", part); + return None; + } + let lines = sm.span_to_lines(part.span).ok()?; + if sm.ensure_source_file_source_present(&lines.file) { + None + } else { + Some(part.span) + } + }) + .collect::>(); + + if spans.is_empty() { None } else { Some(MultiSpan::from_spans(spans)) } + } } fn emit_to_destination( diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 59d79754314c1..29cffb1e3cdda 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -54,6 +54,7 @@ pub struct JsonEmitter { macro_backtrace: bool, track_diagnostics: bool, terminal_url: TerminalUrl, + show_suggestions_with_unavailable_source: bool, } impl JsonEmitter { @@ -76,6 +77,7 @@ impl JsonEmitter { macro_backtrace: false, track_diagnostics: false, terminal_url: TerminalUrl::No, + show_suggestions_with_unavailable_source: false, } } @@ -361,6 +363,7 @@ impl Diagnostic { .terminal_url(je.terminal_url) .ui_testing(je.ui_testing) .ignored_directories_in_source_blocks(je.ignored_directories_in_source_blocks.clone()) + .show_suggestions_with_unavailable_source(je.show_suggestions_with_unavailable_source) .theme(if je.json_rendered.unicode { OutputTheme::Unicode } else { OutputTheme::Ascii }) .emit_diagnostic(diag); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 204b6f913cb8b..e8a421afacabd 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -86,6 +86,7 @@ fn check_method_is_structurally_compatible<'tcx>( compare_self_type(tcx, impl_m, trait_m, impl_trait_ref, delay)?; compare_number_of_generics(tcx, impl_m, trait_m, delay)?; compare_generic_param_kinds(tcx, impl_m, trait_m, delay)?; + compare_const_generic_param_types(tcx, impl_m, trait_m, impl_trait_ref, delay)?; compare_number_of_method_arguments(tcx, impl_m, trait_m, delay)?; compare_synthetic_generics(tcx, impl_m, trait_m, delay)?; check_region_bounds_on_impl_item(tcx, impl_m, trait_m, delay)?; @@ -2034,31 +2035,8 @@ fn compare_synthetic_generics<'tcx>( if let Some(reported) = error_found { Err(reported) } else { Ok(()) } } -/// Checks that all parameters in the generics of a given assoc item in a trait impl have -/// the same kind as the respective generic parameter in the trait def. -/// -/// For example all 4 errors in the following code are emitted here: -/// ```rust,ignore (pseudo-Rust) -/// trait Foo { -/// fn foo(); -/// type Bar; -/// fn baz(); -/// type Blah; -/// } -/// -/// impl Foo for () { -/// fn foo() {} -/// //~^ error -/// type Bar = (); -/// //~^ error -/// fn baz() {} -/// //~^ error -/// type Blah = u32; -/// //~^ error -/// } -/// ``` -/// -/// This function does not handle lifetime parameters +/// Checks that corresponding generic parameters in a trait item and its impl +/// are both type parameters or both const parameters. fn compare_generic_param_kinds<'tcx>( tcx: TyCtxt<'tcx>, impl_item: ty::AssocItem, @@ -2081,11 +2059,6 @@ fn compare_generic_param_kinds<'tcx>( { use GenericParamDefKind::*; if match (¶m_impl.kind, ¶m_trait.kind) { - (Const { .. }, Const { .. }) - if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) => - { - true - } (Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true, // this is exhaustive so that anyone adding new generic param kinds knows // to make sure this error is reported for them. @@ -2104,7 +2077,7 @@ fn compare_generic_param_kinds<'tcx>( "{} `{}` has an incompatible generic parameter for trait `{}`", impl_item.descr(), trait_item.name(), - &tcx.def_path_str(tcx.parent(trait_item.def_id)) + tcx.def_path_str(tcx.parent(trait_item.def_id)) ); let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind { @@ -2138,6 +2111,98 @@ fn compare_generic_param_kinds<'tcx>( Ok(()) } +/// Checks that corresponding const generic parameters in a trait item and its +/// impl have compatible types. +fn compare_const_generic_param_types<'tcx>( + tcx: TyCtxt<'tcx>, + impl_item: ty::AssocItem, + trait_item: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, + delay: bool, +) -> Result<(), ErrorGuaranteed> { + assert_eq!(impl_item.tag(), trait_item.tag()); + use GenericParamDefKind::*; + + let const_params_of = |def_id| { + tcx.generics_of(def_id).own_params.iter().filter(|param| matches!(param.kind, Const { .. })) + }; + + // Map the trait item's generic parameters into the impl item's generic context. + let trait_to_impl_args = ty::GenericArgs::identity_for_item(tcx, impl_item.def_id).rebase_onto( + tcx, + impl_item.container_id(tcx), + impl_trait_ref.args, + ); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); + let param_env = tcx.param_env(impl_item.def_id); + + let param_iter = + iter::zip(const_params_of(impl_item.def_id), const_params_of(trait_item.def_id)); + + for (param_impl, param_trait) in param_iter { + let param_impl_ty_span = tcx.ty_span(param_impl.def_id.expect_local()); + + let cause = ObligationCause::new( + param_impl_ty_span, + impl_item.def_id.expect_local(), + ObligationCauseCode::CompareImplItem { + impl_item_def_id: impl_item.def_id.expect_local(), + trait_item_def_id: trait_item.def_id, + kind: impl_item.kind, + }, + ); + + let impl_ty = + ocx.normalize(&cause, param_env, tcx.type_of(param_impl.def_id).instantiate_identity()); + + let trait_ty = ocx.normalize( + &cause, + param_env, + tcx.type_of(param_trait.def_id).instantiate(tcx, trait_to_impl_args), + ); + + match ocx.eq(&cause, param_env, trait_ty, impl_ty) { + // Despite returning `Ok` all may not be well. As such, outside of this + // loop we invoke `ocx.evaluate_obligations_error_on_ambiguity()` to check + // for any other errors that may have occurred. + Ok(_) => {} + Err(terr) => { + let param_trait_ty_span = + param_trait.def_id.as_local().map(|def_id| tcx.ty_span(def_id)); + let mut diag = struct_span_code_err!( + tcx.dcx(), + param_impl_ty_span, + E0053, + "{} `{}` has an incompatible type for const generic parameter", + trait_item.descr(), + trait_item.name(), + ); + infcx.err_ctxt().note_type_err( + &mut diag, + &cause, + param_trait_ty_span.map(|span| (span, Cow::from("type in trait"), false)), + Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound { + expected: trait_ty.into(), + found: impl_ty.into(), + }))), + terr, + false, + None, + ); + let reported = diag.emit_err_unless_delay(delay); + return Err(reported); + } + } + } + + if let TraitErrors::HasErrors(errors) = ocx.evaluate_obligations_error_on_ambiguity() { + Err(infcx.err_ctxt().report_fulfillment_errors(errors)) + } else { + Ok(()) + } +} + fn compare_impl_const<'tcx>( tcx: TyCtxt<'tcx>, impl_const_item: ty::AssocItem, @@ -2147,6 +2212,13 @@ fn compare_impl_const<'tcx>( compare_const_directness(tcx, impl_const_item, trait_const_item)?; compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?; compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?; + compare_const_generic_param_types( + tcx, + impl_const_item, + trait_const_item, + impl_trait_ref, + false, + )?; check_region_bounds_on_impl_item(tcx, impl_const_item, trait_const_item, false)?; compare_const_clause_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref) } @@ -2325,6 +2397,7 @@ fn compare_impl_ty<'tcx>( ) -> Result<(), ErrorGuaranteed> { compare_number_of_generics(tcx, impl_ty, trait_ty, false)?; compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?; + compare_const_generic_param_types(tcx, impl_ty, trait_ty, impl_trait_ref, false)?; check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?; compare_type_clause_entailment(tcx, impl_ty, trait_ty, impl_trait_ref)?; check_type_bounds(tcx, trait_ty, impl_ty, impl_trait_ref) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b81b7aafb8c1d..df9a3877b1f15 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1760,28 +1760,27 @@ fn rendered_precise_capturing_args<'tcx>( fn const_param_default<'tcx>( tcx: TyCtxt<'tcx>, - local_def_id: LocalDefId, + param_def_id: LocalDefId, ) -> ty::EarlyBinder<'tcx, Const<'tcx>> { let hir::Node::GenericParam(hir::GenericParam { - kind: hir::GenericParamKind::Const { default: Some(default_ct), .. }, + kind: hir::GenericParamKind::Const { default: Some(ct), .. }, .. - }) = tcx.hir_node_by_def_id(local_def_id) + }) = tcx.hir_node_by_def_id(param_def_id) else { span_bug!( - tcx.def_span(local_def_id), - "`const_param_default` expected a generic parameter with a constant" + tcx.def_span(param_def_id), + "const_param_default: expected a const parameter with a default value" ) }; - let icx = ItemCtxt::new(tcx, local_def_id); + // FIXME: Don't lower in the context of parent. Blocked on the removal of GCE. See comment in + // `type_of.rs` for details (Ctrl+F for `generics_of`). + let item_def_id = tcx.local_parent(param_def_id); + let icx = ItemCtxt::new(tcx, item_def_id); - let def_id = local_def_id.to_def_id(); - let identity_args = ty::GenericArgs::identity_for_item(tcx, tcx.parent(def_id)); - - let ct = icx.lowerer().lower_const_arg( - default_ct, - tcx.type_of(def_id).instantiate(tcx, identity_args).skip_norm_wip(), - ); + let ct = icx + .lowerer() + .lower_const_arg(ct, tcx.type_of(param_def_id).instantiate_identity().skip_norm_wip()); ty::EarlyBinder::bind(tcx, ct) } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 4d43a9ca5700e..74eed3e502e8b 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -211,6 +211,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { Node::Item(_) | Node::ForeignItem(_) => None, // Params don't really have generics, but we use it when instantiating their value paths. + // FIXME: Use the HIR parent here similar to `Node::Field`. Blocked on the removal of GCE, + // see comment in `type_of.rs` for details (Ctrl+F for `generics_of`). Node::GenericParam(_) => None, Node::Synthetic => span_bug!( @@ -236,7 +238,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let opt_self = if let Node::Item(item) = node && let ItemKind::Trait { .. } | ItemKind::TraitAlias(..) = item.kind { - // Something of a hack: We reuse the node ID of the trait for the self type parameter. + // Something of a hack: We reuse the DefId of the trait for the self type parameter. Some(ty::GenericParamDef { index: 0, name: kw::SelfUpper, diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 8754430aaa99e..4beefa905a134 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -59,10 +59,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ None => {} } - let hir_id = tcx.local_def_id_to_hir_id(def_id); - - let icx = ItemCtxt::new(tcx, def_id); - let new_bound_fn_def = |hir: HirId, did| { let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def( @@ -80,7 +76,21 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ) }; - let output = match tcx.hir_node(hir_id) { + let hir_id = tcx.local_def_id_to_hir_id(def_id); + let hir_node = tcx.hir_node(hir_id); + let def_id = match hir_node { + // For generic params, we lower in the context of the overarching item to be able to resolve + // type-relative paths in type param defaults & const param types. + // FIXME: Remove this special case again & simply set the `Generics.parent` for generic + // params in `generics_of` similar to struct fields. However, that's blocked on the + // removal of GCE in favor of mGCA. Doing this change now would introduce tons of + // query cycles for GCE. + Node::GenericParam(_) => tcx.local_parent(def_id), + _ => def_id, + }; + let icx = ItemCtxt::new(tcx, def_id); + + let output = match hir_node { Node::TraitItem(item) => match item.kind { TraitItemKind::Fn(_, _) => new_bound_fn_def(item.hir_id(), def_id.to_def_id()), TraitItemKind::Const(ty, rhs) => rhs @@ -104,7 +114,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ .unwrap_or_else(|| icx.lower_ty(ty)), TraitItemKind::Type(_, Some(ty)) => icx.lower_ty(ty), TraitItemKind::Type(_, None) => { - span_bug!(item.span, "associated type missing default"); + span_bug!(item.span, "type_of: associated type missing default"); } }, @@ -207,7 +217,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ | ItemKind::ExternCrate(..) | ItemKind::Use(..) | ItemKind::TestBinderConstraints { .. } => { - span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind); + span_bug!(item.span, "type_of: unexpected item kind: {:?}", item.kind); } }, @@ -263,12 +273,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ lowered_ty } } - x => bug!("unexpected non-type Node::GenericParam: {:?}", x), + _ => bug!("type_of: unexpected node kind {hir_node:?}"), }, - x => { - bug!("unexpected sort of node in type_of(): {:?}", x); - } + node => bug!("type_of: unexpected node kind: {node:?}"), }; if let Err(e) = icx.check_tainted_by_errors() && !output.references_error() diff --git a/compiler/rustc_hir_typeck/src/diagnostics.rs b/compiler/rustc_hir_typeck/src/diagnostics.rs index 5522ce033ee9c..0b4a88500aaaa 100644 --- a/compiler/rustc_hir_typeck/src/diagnostics.rs +++ b/compiler/rustc_hir_typeck/src/diagnostics.rs @@ -687,6 +687,30 @@ pub(crate) struct SuggestPtrNullMut { pub span: Span, } +#[derive(Subdiagnostic)] +#[suggestion( + "consider using `&mut` instead", + applicability = "maybe-incorrect", + style = "verbose", + code = "&mut " +)] +pub(crate) struct SuggestRefMut { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion( + "consider using `&raw mut` instead", + applicability = "maybe-incorrect", + style = "verbose", + code = "&raw mut " +)] +pub(crate) struct SuggestRawMut { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag( "trivial {$numeric -> diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 8ecd7838a0e69..68eb349bab8f0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -37,7 +37,7 @@ use crate::Expectation::*; use crate::TupleArgumentsFlag::*; use crate::callee::SplatLoweringInfo; use crate::coercion::CoerceMany; -use crate::diagnostics::{ExprParenthesesNeeded, SuggestPtrNullMut}; +use crate::diagnostics::{ExprParenthesesNeeded, SuggestPtrNullMut, SuggestRawMut, SuggestRefMut}; use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; use crate::gather_locals::Declaration; use crate::inline_asm::InlineAsmCtxt; @@ -982,23 +982,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit_err() } - fn suggest_ptr_null_mut( + fn suggest_mut_addr( &self, expected_ty: Ty<'tcx>, provided_ty: Ty<'tcx>, arg: &hir::Expr<'tcx>, err: &mut Diag<'_>, ) { - if let ty::RawPtr(_, hir::Mutability::Mut) = expected_ty.kind() - && let ty::RawPtr(_, hir::Mutability::Not) = provided_ty.kind() - && let hir::ExprKind::Call(callee, _) = arg.kind - && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind - && let Res::Def(_, def_id) = path.res - && self.tcx.get_diagnostic_item(sym::ptr_null) == Some(def_id) - { + match (expected_ty.kind(), provided_ty.kind(), arg.kind) { // The user provided `ptr::null()`, but the function expects // `ptr::null_mut()`. - err.subdiagnostic(SuggestPtrNullMut { span: arg.span }); + ( + ty::RawPtr(_, hir::Mutability::Mut), + ty::RawPtr(_, hir::Mutability::Not), + hir::ExprKind::Call(callee, _), + ) if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind + && let Res::Def(_, def_id) = path.res + && self.tcx.get_diagnostic_item(sym::ptr_null) == Some(def_id) => + { + err.subdiagnostic(SuggestPtrNullMut { span: arg.span }); + } + // &mut T expected, &T or *const/mut T found + // suggestion: replace `&` or `&raw const/mut` with `&mut` + ( + ty::Ref(_, expected_ty, hir::Mutability::Mut), + ty::Ref(_, provided_ty, hir::Mutability::Not), + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr), + ) + | ( + ty::Ref(_, expected_ty, hir::Mutability::Mut), + ty::RawPtr(provided_ty, _), + hir::ExprKind::AddrOf(hir::BorrowKind::Raw, _, expr), + ) if expected_ty == provided_ty => { + let span = arg.span.until(expr.span); + err.subdiagnostic(SuggestRefMut { span }); + } + // *mut T expected, *const T found + // suggestion: replace `&raw const` with `&raw mut` + ( + ty::RawPtr(expected_ty, hir::Mutability::Mut), + ty::RawPtr(provided_ty, hir::Mutability::Not), + hir::ExprKind::AddrOf(hir::BorrowKind::Raw, hir::Mutability::Not, expr), + ) if expected_ty == provided_ty => { + let span = arg.span.until(expr.span); + err.subdiagnostic(SuggestRawMut { span }); + } + // *mut T expected, &T found + // suggestion: replace `&` `&mut` + ( + ty::RawPtr(expected_ty, hir::Mutability::Mut), + ty::Ref(_, provided_ty, hir::Mutability::Not), + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr), + ) if expected_ty == provided_ty => { + let span = arg.span.until(expr.span); + err.subdiagnostic(SuggestRefMut { span }); + } + _ => {} } } @@ -2491,7 +2530,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> { ); } - self.suggest_ptr_null_mut( + self.suggest_mut_addr( expected_ty, provided_ty, self.provided_args[provided_idx], diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a29309c71e879..d5bc54ffb1647 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2883,6 +2883,8 @@ written to standard error output)"), "make the current crate share its generic instantiations"), shell_argfiles: bool = (false, parse_bool, [UNTRACKED], "allow argument files to be specified with POSIX \"shell-style\" argument quoting"), + show_suggestions_with_unavailable_source: bool = (false, parse_bool, [UNTRACKED], + "show span-only suggestions when the source code is unavailable"), simulate_remapped_rust_src_base: Option = (None, parse_opt_pathbuf, [TRACKED], "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \ to rust's source base directory. only meant for testing purposes"), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f068aaa584dce..66c5f7740a011 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1282,6 +1282,8 @@ impl Session { fn default_emitter(sopts: &config::Options, source_map: Arc) -> Box { let macro_backtrace = sopts.unstable_opts.macro_backtrace; let track_diagnostics = sopts.unstable_opts.track_diagnostics; + let show_suggestions_with_unavailable_source = + sopts.unstable_opts.show_suggestions_with_unavailable_source; let terminal_url = match sopts.unstable_opts.terminal_urls { TerminalUrl::Auto => { match (std::env::var("COLORTERM").as_deref(), std::env::var("TERM").as_deref()) { @@ -1309,6 +1311,9 @@ fn default_emitter(sopts: &config::Options, source_map: Arc) -> Box) -> Box BestObligation<'tcx> { // We always handle rigid alias candidates separately as we may not add them for // aliases whose trait bound doesn't hold. candidates.retain(|c| !matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. })); - // If we have >1 candidate, one may still be due to "boring" reasons, like - // an alias-relate that failed to hold when deeply evaluated. We really - // don't care about reasons like this. + // If there are multiple candidates, we can still recurse into a single one if all + // others fail due to boring reasons. Currently that's if we fail to normalize + // while considering the candidate. if candidates.len() > 1 { candidates.retain(|candidate| { goal.infcx().probe(|_| { - candidate.instantiate_nested_goals(self.span()).iter().any( + !candidate.instantiate_nested_goals(self.span()).iter().any( |nested_goal| { - matches!( - nested_goal.source(), - GoalSource::ImplWhereBound - | GoalSource::AliasBoundConstCondition - | GoalSource::AliasWellFormed - ) && nested_goal.result().is_err() + nested_goal.source() == GoalSource::Normalization + && nested_goal.result().is_err() }, ) }) diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index be05ed2cd4d81..4a6e704cb0020 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -52,6 +52,7 @@ use crate::data_structures::IndexMap; use crate::fold::TypeSuperFoldable; use crate::inherent::*; use crate::relate::{Relate, RelateResult, TypeRelation, VarianceDiagInfo}; +use crate::visit::TypeVisitableExt; use crate::{ AliasTy, Binder, BoundRegion, BoundVar, BoundVariableKind, ClauseKind, DebruijnIndex, InferCtxtLike, Interner, IsRigid, OutlivesClause, Region, RegionKind, TyKind, TypeFoldable, @@ -59,7 +60,7 @@ use crate::{ set_aliases_to_non_rigid, }; -#[derive_where(Clone, Debug; I: Interner)] +#[derive_where(Clone; I: Interner)] pub struct Assumptions { pub type_outlives: Vec>>, /// Known `'a: 'b` assumptions, stored as an edge from the outliving region to the @@ -70,6 +71,15 @@ pub struct Assumptions { pub inverse_region_outlives: TransitiveRelation>, } +impl std::fmt::Debug for Assumptions { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + f.debug_struct("Assumptions") + .field("type_outlives", &self.type_outlives) + .field("region_graph", &"elided") + .finish() + } +} + impl Assumptions { pub fn empty() -> Self { Self { @@ -156,10 +166,10 @@ impl Assumptions { } } -#[derive_where(Clone, Hash, PartialEq, Eq, Debug; I: Interner, S)] +#[derive_where(Clone, Hash, PartialEq, Eq; I: Interner, S)] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(StableHash_NoContext))] -pub enum LeafRegionConstraint { +pub enum LeafRegionConstraint { Ambiguity(S), RegionOutlives(Region, Region, S), /// Requirement that a (potentially higher ranked) alias outlives some (potentially higher ranked) @@ -184,6 +194,23 @@ pub enum LeafRegionConstraint { PlaceholderTyOutlives(I::Ty, Region, S), } +impl std::fmt::Debug for LeafRegionConstraint { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + match self { + Self::Ambiguity(_span) => write!(f, "Ambiguity"), + Self::RegionOutlives(r1, r2, _span) => { + f.debug_tuple("RegionOutlives").field(r1).field(r2).finish() + } + Self::AliasTyOutlivesViaEnv(bound_outlives, _span) => { + f.debug_tuple("AliasTyOutlivesViaEnv").field(bound_outlives).finish() + } + Self::PlaceholderTyOutlives(ty, r, _span) => { + f.debug_tuple("PlaceholderTyOutlives").field(ty).field(r).finish() + } + } + } +} + impl LeafRegionConstraint { pub fn with_span( self, @@ -861,6 +888,7 @@ fn rewrite_type_outlives_constraints_in_universe_for_eager_placeholder_handling< RegionConstraint::new_from_or(Or::build_and(and_constraint, or_constraint)) } +#[instrument(level = "debug", skip(infcx), ret)] fn rewrite_placeholder_ty_outlives_constraints_in_universe_for_eager_placeholder_handling< Infcx: InferCtxtLike, I: Interner, @@ -903,6 +931,7 @@ fn rewrite_placeholder_ty_outlives_constraints_in_universe_for_eager_placeholder Or::new(candidates.into_iter().map(|c| And::new([c]))) } +#[instrument(level = "debug", skip(infcx), ret)] fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handling< Infcx: InferCtxtLike, I: Interner, @@ -914,12 +943,15 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl ) -> Or { use LeafRegionConstraint::*; + if max_universe(infcx, bound_outlives) != u { + return Or::new_leaf(AliasTyOutlivesViaEnv(bound_outlives, ())); + } + let mut candidates = Vec::new(); // given there can be higher ranked assumptions, e.g. `for<'a> >::Assoc: 'c`, that // means that it's actually *always* possible for an alias outlive to be satisfied in the root universe - // which means there should *always* be atleast two candidates when destructuring alias outlives. The - // two candidates being component outlives and then a higher ranked alias outlives. + // which means there should *always* be atleast one candidate when destructuring alias outlives. // // we dont care about this for region outlives as `for<'a> 'a: 'b` can't exist as we don't elaborate // higher ranked type outlives assumptions into higher ranked region outlives assumptions. similarly, @@ -929,9 +961,9 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl // // so actually only `for<'a, 'b> Alias<'a>: 'b` and `for<'a> T: 'a` are assumptions we actually need to // handle. - // - // we don't care about this when rewriting in the root universe as we know the complete set of assumptions - if max_universe(infcx, bound_outlives) == u { + let higher_ranked_candidate_for_outlived_region = |region| { + let bound_outlives = bound_outlives.map_bound(|(alias, _)| (alias, region)); + let mut replacer = PlaceholderReplacer { cx: infcx.cx(), existing_var_count: bound_outlives.bound_vars().len(), @@ -949,61 +981,42 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl escaping_outlives, I::BoundVarKinds::from_vars(infcx.cx(), bound_vars), ); - let candidate = Or::new_leaf(AliasTyOutlivesViaEnv(bound_outlives, ())); - if max_universe(infcx, candidate.clone()) < u { - candidates.push(candidate); - } else { - // `PlaceholderReplacer` only folds regions. A non-lifetime binder can leave - // a placeholder type in `u`, so this type-outlives constraint cannot be - // handled by the region-outlives-only eager placeholder machinery. - candidates.push(Or::new_ambig(())); + + // `PlaceholderReplacer` only folds regions. A non-lifetime binder can leave + // a placeholder type in `u`, so this type-outlives constraint cannot be + // handled by the region-outlives-only eager placeholder machinery. + if max_universe(infcx, bound_outlives) == u { + return Or::new_ambig(()); } - } - // Actually look at the assumptions and matching our higher ranked alias outlives goal - // against potentially higher ranked type outlives assumptions. - candidates.push(alias_outlives_candidates_from_assumptions(infcx, bound_outlives, assumptions)); + debug!("higher ranked candidate: {bound_outlives:?}"); + Or::new_leaf(AliasTyOutlivesViaEnv(bound_outlives, ())) + }; - // we can rewrite `Alias_u1: 'u2` into `Or(Alias_u1: 'u1)` - // given a list of regions which outlive `'u2` + // We elaborate something like `Alias<'a_u2>: 'b_u2` into alias outlives involving each + // region which is known to outlive `'b_u2`. So e.g. if `'c_u2: 'b_u2` is known to hold + // would wind up looking at `Alias<'a_u2>: 'c_u2` as well as `Alias<'a_u2>: 'b_u2`. // - // we don't care about this when rewriting in the root universe as we know the complete set of assumptions - let (escaping_alias, escaping_r) = bound_outlives.skip_binder(); - if max_universe(infcx, escaping_r) == u { - let mut replacer = PlaceholderReplacer { - cx: infcx.cx(), - existing_var_count: bound_outlives.bound_vars().len(), - bound_vars: IndexMap::default(), - universe: u, - current_index: DebruijnIndex::ZERO, - }; - let escaping_alias = escaping_alias.fold_with(&mut replacer); - let bound_vars = bound_outlives.bound_vars().iter().chain( - core::mem::take(&mut replacer.bound_vars) - .into_iter() - .map(|(_, bound_region)| BoundVariableKind::Region(bound_region.kind)), - ); - let bound_alias = Binder::bind_with_vars( - escaping_alias, - I::BoundVarKinds::from_vars(infcx.cx(), bound_vars), - ); + // This is important in two cases. First, if the outliving region is in a lower universe then + // we've successfully lowered the universe of one of the terms in our alias outlives constraint. + // + // Secondly, if it's a region in the current universe *and* it's a region in the components of the + // alias then we get a less general constraint after replacing with bound vars compared to if we + // had just replaced the initial region. See `assumptions_on_binders/alias_outlives_with_repeated_placeholder.rs` + let escaping_r = bound_outlives.skip_binder().1; + if max_universe(infcx, escaping_r) < u || escaping_r.has_escaping_bound_vars() { + // we don't know anything about lower universe regions, and we also don't bother + // looking at the assumptions on the `AliasTyOutlivesViaEnv` binder. + candidates.push(higher_ranked_candidate_for_outlived_region(escaping_r)) + } else { + for r in regions_outliving(escaping_r, assumptions, infcx.cx()) { + candidates.push(higher_ranked_candidate_for_outlived_region(r)); + } + }; - // while we did skip the binder, bound vars aren't in any universe so - // this can't be an escaping bound var - candidates.push(Or::new( - regions_outliving(escaping_r, assumptions, infcx.cx()) - .filter(|r2| max_universe(infcx, *r2) < u) - .map(|r2| { - let candidate = - AliasTyOutlivesViaEnv(bound_alias.map_bound(|alias| (alias, r2)), ()); - if max_universe(infcx, candidate.clone()) < u { - And::new([candidate]) - } else { - And::new([Ambiguity(())]) - } - }), - )); - } + // Actually look at the assumptions and matching our higher ranked alias outlives goal + // against potentially higher ranked type outlives assumptions. + candidates.push(alias_outlives_candidates_from_assumptions(infcx, bound_outlives, assumptions)); // I'm not convinced our handling here is *complete* so for now // let's be conservative and not let alias outlives' cause NoSolution diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 0a6e351dcdf8f..e427cdcdc8acb 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -763,7 +763,7 @@ impl, X: Cx> SearchGraph { #[allow(rustc::potential_query_instability)] for (head_index, usages) in usages.into_iter() { if head_index == entry_index { - entry.usages.unwrap().ignore_usages(usages); + entry.usages.as_mut().unwrap().ignore_usages(usages); } else { entry.heads.ignore_usages(head_index, usages); } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index ceaa28fc4bdb8..c532b670dbef1 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -4587,14 +4587,6 @@ impl CommandLineStep for CodegenGCC { return; } - let triple = run.target.triple; - let target_supported = - if triple.contains("linux") { triple.contains("x86_64") } else { false }; - if !target_supported { - builder.info("target not supported by rustc_codegen_gcc. skipping"); - return; - } - if builder.remote_tested(run.target) { builder.info("remote testing is not supported by rustc_codegen_gcc. skipping"); return; @@ -4976,7 +4968,7 @@ impl CommandLineStep for StdSemverCheck { res.stdout() ); if builder.fail_fast { - eprintln!("{error}",); + eprintln!("{error}"); helpers::exit_process(1); } else { builder.config.exec_ctx().add_to_delay_failure(error); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 263c8d5aded54..a8ef469de438a 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1794,6 +1794,7 @@ impl<'test> TestCx<'test> { compiler.arg("-Ccodegen-units=1"); // Hide line numbers to reduce churn compiler.arg("-Zui-testing"); + compiler.arg("-Zshow-suggestions-with-unavailable-source"); compiler.arg("-Zdeduplicate-diagnostics=no"); compiler.arg("-Zwrite-long-types-to-disk=no"); // FIXME: use this for other modes too, for perf? diff --git a/tests/ui/associated-types/issue-38821.stderr b/tests/ui/associated-types/issue-38821.stderr index ad59184366ae1..19f813156da5b 100644 --- a/tests/ui/associated-types/issue-38821.stderr +++ b/tests/ui/associated-types/issue-38821.stderr @@ -81,6 +81,21 @@ LL | impl IntoNullable for T { | unsatisfied trait bound introduced here = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:10 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied --> $DIR/issue-38821.rs:35:10 | @@ -210,6 +225,21 @@ LL | impl IntoNullable for T { | unsatisfied trait bound introduced here = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied + --> $DIR/issue-38821.rs:23:23 + | +LL | #[derive(Debug, Copy, Clone)] + | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` + | +note: required for `::SqlType` to implement `IntoNullable` + --> $DIR/issue-38821.rs:9:18 + | +LL | impl IntoNullable for T { + | ------- ^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied --> $DIR/issue-38821.rs:35:10 | @@ -257,36 +287,6 @@ LL | impl IntoNullable for T { | unsatisfied trait bound introduced here = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:23:10 - | -LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` - | -note: required for `::SqlType` to implement `IntoNullable` - --> $DIR/issue-38821.rs:9:18 - | -LL | impl IntoNullable for T { - | ------- ^^^^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied - --> $DIR/issue-38821.rs:23:23 - | -LL | #[derive(Debug, Copy, Clone)] - | ^^^^^ the trait `NotNull` is not implemented for `::SqlType` - | -note: required for `::SqlType` to implement `IntoNullable` - --> $DIR/issue-38821.rs:9:18 - | -LL | impl IntoNullable for T { - | ------- ^^^^^^^^^^^^ ^ - | | - | unsatisfied trait bound introduced here - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0277]: the trait bound `::SqlType: NotNull` is not satisfied --> $DIR/issue-38821.rs:23:23 | diff --git a/tests/ui/associated-types/type-relative-in-const-param-ty.rs b/tests/ui/associated-types/type-relative-in-const-param-ty.rs new file mode 100644 index 0000000000000..e10ced8d30fa4 --- /dev/null +++ b/tests/ui/associated-types/type-relative-in-const-param-ty.rs @@ -0,0 +1,21 @@ +// Test that we can resolve type-relative associated type paths inside const parameter types +// where the self type is a simple type parameter. + +//@ check-pass +#![feature(generic_const_parameter_types, adt_const_params, const_param_ty_trait)] + +trait Trait { + type Type; +} + +// Below, `T::Type` resolves to `::Type` since the owner has bound `T: Trait`. + +struct Owner0(T) +where + T: Trait; + +struct Owner1(T) +where + T: Trait; + +fn main() {} diff --git a/tests/ui/associated-types/type-relative-in-ty-param-default.rs b/tests/ui/associated-types/type-relative-in-ty-param-default.rs new file mode 100644 index 0000000000000..33aae581708c8 --- /dev/null +++ b/tests/ui/associated-types/type-relative-in-ty-param-default.rs @@ -0,0 +1,20 @@ +// Test that we can resolve type-relative associated type paths inside type parameter defaults +// where the self type is a simple type parameter. +// +// issue: + +//@ check-pass + +trait Trait { + type Type; +} + +// Below, `T::Type` resolves to `::Type` since the owner has bound `T: Trait`. + +struct Owner0(T, U); + +struct Owner1(T, U) +where + T: Trait; + +fn main() {} diff --git a/tests/ui/assumptions_on_binders/alias_outlives_with_repeated_placeholder.rs b/tests/ui/assumptions_on_binders/alias_outlives_with_repeated_placeholder.rs new file mode 100644 index 0000000000000..b1fa6f7f910a3 --- /dev/null +++ b/tests/ui/assumptions_on_binders/alias_outlives_with_repeated_placeholder.rs @@ -0,0 +1,34 @@ +//@ check-pass +//@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally + +#![feature(test_binder_constraints, non_lifetime_binders)] +#![expect(incomplete_features)] + +trait Trait<'a> { + type Assoc; +} + +core::test_binder_constraints! { + impl + where + for<'a> T: Trait<'a>, + for<'a> >::Assoc: 'a + { + forall<'a, 'b> + where + 'a: 'b, + { + for<> >::Assoc: 'b + } expect { + or { + // this first candidate is the important one! + for<'a> >::Assoc: 'a, + // these won't wind up actually being used to prove the OR + for<'a, 'b> >::Assoc: 'b, + for<'a> >::Assoc: 'static, + } + } + } +} + +fn main() {} diff --git a/tests/ui/assumptions_on_binders/lower_universe_alias_outlives.rs b/tests/ui/assumptions_on_binders/lower_universe_alias_outlives.rs new file mode 100644 index 0000000000000..f547295419c4f --- /dev/null +++ b/tests/ui/assumptions_on_binders/lower_universe_alias_outlives.rs @@ -0,0 +1,26 @@ +//@ check-pass + +// test that we don't incorrectly try and eagerly handle alias outlives' from too +// low a universe + +#![feature(test_binder_constraints, generic_const_items)] + +trait AliasHaver { + type Assoc; +} + +core::test_binder_constraints! { + impl + where + T::Assoc: 'static, + { + forall<'b> { + for<> T::Assoc: 'static + } expect { + // previously this would just be `or {}` i.e. false + for<> T::Assoc: 'static + } + } +} + +fn main() {} diff --git a/tests/ui/assumptions_on_binders/test-infra-fails-properly.stderr b/tests/ui/assumptions_on_binders/test-infra-fails-properly.stderr index 04eb93f7fe03c..5736d8ef5dbaa 100644 --- a/tests/ui/assumptions_on_binders/test-infra-fails-properly.stderr +++ b/tests/ui/assumptions_on_binders/test-infra-fails-properly.stderr @@ -72,12 +72,10 @@ LL | forall<'a> where 'b: 'a { = note: expected: RegionOutlives( 'b/#0, 'c/#1, - $DIR/test-infra-fails-properly.rs:64:17: 64:23 (#0), ) = note: actual: RegionOutlives( 'c/#1, 'static, - $DIR/test-infra-fails-properly.rs:59:9: 59:15 (#0), ) error: bound type test binder constraint must be alias (it's a AliasTyOutlivesViaEnv) @@ -110,9 +108,7 @@ LL | ambiguity | = note: expected: And( [ - Ambiguity( - $DIR/test-infra-fails-properly.rs:91:13: 91:22 (#0), - ), + Ambiguity, ], ) = note: actual: And( @@ -135,9 +131,7 @@ LL | forall<'a> where 'a: 'static { ) = note: actual: And( [ - Ambiguity( - $DIR/test-infra-fails-properly.rs:99:9: 99:15 (#0), - ), + Ambiguity, ], ) diff --git a/tests/ui/async-await/in-trait/generics-mismatch.rs b/tests/ui/async-await/in-trait/generics-mismatch.rs index a5c81a9299810..f928d975f1a30 100644 --- a/tests/ui/async-await/in-trait/generics-mismatch.rs +++ b/tests/ui/async-await/in-trait/generics-mismatch.rs @@ -6,7 +6,7 @@ trait Foo { impl Foo for () { async fn foo() {} - //~^ ERROR: associated function `foo` has an incompatible generic parameter for trait `Foo` [E0053] + //~^ ERROR: associated function `foo` has an incompatible generic parameter for trait `Foo` } fn main() {} diff --git a/tests/ui/const-generics/auxiliary/non_local.rs b/tests/ui/const-generics/auxiliary/non_local.rs new file mode 100644 index 0000000000000..38a030d610be6 --- /dev/null +++ b/tests/ui/const-generics/auxiliary/non_local.rs @@ -0,0 +1,3 @@ +pub trait NonLocal { + fn method(); +} diff --git a/tests/ui/const-generics/ban-self-when-feature-not-enabled.rs b/tests/ui/const-generics/ban-self-when-feature-not-enabled.rs index 49241033b7251..cac6009f987a8 100644 --- a/tests/ui/const-generics/ban-self-when-feature-not-enabled.rs +++ b/tests/ui/const-generics/ban-self-when-feature-not-enabled.rs @@ -7,7 +7,6 @@ trait MyTrait { impl MyTrait for i32 { fn foo() {} //~^ ERROR cannot use `Self` in const parameter type - //~| ERROR associated function `foo` has an incompatible generic parameter for trait `MyTrait` } fn main(){} diff --git a/tests/ui/const-generics/ban-self-when-feature-not-enabled.stderr b/tests/ui/const-generics/ban-self-when-feature-not-enabled.stderr index 4a74de9d5665f..ed44be85780ad 100644 --- a/tests/ui/const-generics/ban-self-when-feature-not-enabled.stderr +++ b/tests/ui/const-generics/ban-self-when-feature-not-enabled.stderr @@ -6,17 +6,5 @@ LL | fn foo() {} | = help: add `#![feature(min_adt_const_params)]` to the crate attributes to enable `Self` as a const parameter type -error[E0053]: associated function `foo` has an incompatible generic parameter for trait `MyTrait` - --> $DIR/ban-self-when-feature-not-enabled.rs:8:12 - | -LL | trait MyTrait { -LL | fn foo(); - | ------------ expected const parameter of type `i32` -... -LL | impl MyTrait for i32 { -LL | fn foo() {} - | ^^^^^^^^^^^^^ found const parameter of type `{type error}` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs index 9eb33acbb24d1..1726bbf34d248 100644 --- a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs +++ b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs @@ -3,7 +3,7 @@ trait Trait { } impl Trait for () { fn foo() {} - //~^ error: associated function `foo` has an incompatible generic parameter for trait + //~^ error: associated function `foo` has an incompatible generic parameter for trait `Trait` } trait Other { @@ -11,7 +11,7 @@ trait Other { } impl Other for () { fn bar() {} - //~^ error: associated function `bar` has an incompatible generic parameter for trait + //~^ error: associated function `bar` has an incompatible generic parameter for trait `Other` } trait Uwu { @@ -19,7 +19,7 @@ trait Uwu { } impl Uwu for () { fn baz() {} - //~^ error: associated function `baz` has an incompatible generic parameter for trait + //~^ error: associated function `baz` has an incompatible type for const generic parameter } trait Aaaaaa { @@ -27,7 +27,7 @@ trait Aaaaaa { } impl Aaaaaa for () { fn bbbb() {} - //~^ error: associated function `bbbb` has an incompatible generic parameter for trait + //~^ error: associated function `bbbb` has an incompatible generic parameter for trait `Aaaaaa` } trait Names { @@ -35,7 +35,7 @@ trait Names { } impl Names for () { fn abcd() {} - //~^ error: associated function `abcd` has an incompatible generic parameter for trait + //~^ error: associated function `abcd` has an incompatible generic parameter for trait `Names` } fn main() {} diff --git a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr index cb37701f9ad37..e279d586c9f5d 100644 --- a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr +++ b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr @@ -20,16 +20,17 @@ LL | impl Other for () { LL | fn bar() {} | ^ found type parameter -error[E0053]: associated function `baz` has an incompatible generic parameter for trait `Uwu` - --> $DIR/mismatched_ty_const_in_trait_impl.rs:21:12 +error[E0053]: associated function `baz` has an incompatible type for const generic parameter + --> $DIR/mismatched_ty_const_in_trait_impl.rs:21:21 | -LL | trait Uwu { -LL | fn baz() {} - | ------------ expected const parameter of type `u32` -LL | } -LL | impl Uwu for () { LL | fn baz() {} - | ^^^^^^^^^^^^ found const parameter of type `i32` + | ^^^ expected `u32`, found `i32` + | +note: type in trait + --> $DIR/mismatched_ty_const_in_trait_impl.rs:18:21 + | +LL | fn baz() {} + | ^^^ error[E0053]: associated function `bbbb` has an incompatible generic parameter for trait `Aaaaaa` --> $DIR/mismatched_ty_const_in_trait_impl.rs:29:13 diff --git a/tests/ui/const-generics/defaults/type-relative-assoc-const.rs b/tests/ui/const-generics/defaults/type-relative-assoc-const.rs new file mode 100644 index 0000000000000..822825d4e01bf --- /dev/null +++ b/tests/ui/const-generics/defaults/type-relative-assoc-const.rs @@ -0,0 +1,16 @@ +// Test that we can resolve type-relative associated const paths inside const parameter defaults +// where the self type is a simple type parameter. + +//@ check-pass +#![feature(gca_min_const_items, gca_macroless_args)] + +trait Trait { + #[rustc_always_gca] + const CT: usize; +} + +// Below, `T::CT` resolves to `::CT` since the owner has bound `T: Trait`. + +struct Owner(T); + +fn main() {} diff --git a/tests/ui/const-generics/issues/issue-86820.rs b/tests/ui/const-generics/issues/issue-86820.rs index ae4bd943fd415..c2c0c1a8d0390 100644 --- a/tests/ui/const-generics/issues/issue-86820.rs +++ b/tests/ui/const-generics/issues/issue-86820.rs @@ -14,7 +14,7 @@ trait Bits { impl Bits for u8 { fn bit(self) -> bool { - //~^ ERROR: method `bit` has an incompatible generic parameter for trait `Bits` [E0053] + //~^ ERROR: method `bit` has an incompatible type for const generic parameter [E0053] let i = 1 << I; let mask = u8::from(i); mask & self == mask diff --git a/tests/ui/const-generics/issues/issue-86820.stderr b/tests/ui/const-generics/issues/issue-86820.stderr index fda12fbda3af4..9f0c896771926 100644 --- a/tests/ui/const-generics/issues/issue-86820.stderr +++ b/tests/ui/const-generics/issues/issue-86820.stderr @@ -1,13 +1,14 @@ -error[E0053]: method `bit` has an incompatible generic parameter for trait `Bits` - --> $DIR/issue-86820.rs:16:12 +error[E0053]: method `bit` has an incompatible type for const generic parameter + --> $DIR/issue-86820.rs:16:21 | -LL | trait Bits { -LL | fn bit(self) -> bool; - | ----------- expected const parameter of type `u8` -... -LL | impl Bits for u8 { LL | fn bit(self) -> bool { - | ^^^^^^^^^^^^^^ found const parameter of type `usize` + | ^^^^^ expected `u8`, found `usize` + | +note: type in trait + --> $DIR/issue-86820.rs:12:21 + | +LL | fn bit(self) -> bool; + | ^^ error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/malformed-parse.rs b/tests/ui/const-generics/malformed-parse.rs new file mode 100644 index 0000000000000..9f5adff63a31f --- /dev/null +++ b/tests/ui/const-generics/malformed-parse.rs @@ -0,0 +1,15 @@ +//@ compile-flags: --crate-type lib + +trait Foo { + fn hello(); +} + +struct Bar; + +impl Foo for Bar { + //~^ ERROR: not all trait items implemented, missing: `hello` + fn hello() { + //~^ ERROR: expected type, found `>` + println!("woof woof") + } +} diff --git a/tests/ui/const-generics/malformed-parse.stderr b/tests/ui/const-generics/malformed-parse.stderr new file mode 100644 index 0000000000000..f30ee07d0c594 --- /dev/null +++ b/tests/ui/const-generics/malformed-parse.stderr @@ -0,0 +1,24 @@ +error: expected type, found `>` + --> $DIR/malformed-parse.rs:11:23 + | +LL | impl Foo for Bar { + | - while parsing this item list starting here +LL | +LL | fn hello() { + | ^ expected type +... +LL | } + | - the item list ends here + +error[E0046]: not all trait items implemented, missing: `hello` + --> $DIR/malformed-parse.rs:9:1 + | +LL | fn hello(); + | ------------------------- `hello` from trait +... +LL | impl Foo for Bar { + | ^^^^^^^^^^^^^^^^ missing `hello` in implementation + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/const-generics/method-instantiation.rs b/tests/ui/const-generics/method-instantiation.rs new file mode 100644 index 0000000000000..c04786c7e75d4 --- /dev/null +++ b/tests/ui/const-generics/method-instantiation.rs @@ -0,0 +1,16 @@ +//@ compile-flags: --crate-type lib +//@ check-pass + +#![feature(min_adt_const_params)] +#![feature(generic_const_parameter_types)] +#![allow(incomplete_features)] + +pub trait Trait { + fn method(); +} + +pub struct Foo; + +impl Trait for Foo { + fn method() {} +} diff --git a/tests/ui/const-generics/method-instatiation-from-const.rs b/tests/ui/const-generics/method-instatiation-from-const.rs new file mode 100644 index 0000000000000..b78523d4e6904 --- /dev/null +++ b/tests/ui/const-generics/method-instatiation-from-const.rs @@ -0,0 +1,18 @@ +//@ compile-flags: --crate-type lib +//@ check-pass + +#![feature(generic_const_parameter_types, min_adt_const_params)] +#![allow(incomplete_features)] + +const FOO: usize = 5; +const BAR: usize = 5; + +pub trait Trait { + fn method(); +} + +pub struct Foo; + +impl Trait for Foo { + fn method() {} +} diff --git a/tests/ui/const-generics/non-local-method.rs b/tests/ui/const-generics/non-local-method.rs new file mode 100644 index 0000000000000..290d7fc903eff --- /dev/null +++ b/tests/ui/const-generics/non-local-method.rs @@ -0,0 +1,15 @@ +//@ compile-flags: --crate-type lib +//@ aux-build:non_local.rs + +extern crate non_local; + +use non_local::NonLocal; + +struct Local; + +impl NonLocal for Local { + fn method() { + //~^ ERROR: associated function `method` has an incompatible type for const generic parameter [E0053] + print!("hello\n"); + } +} diff --git a/tests/ui/const-generics/non-local-method.stderr b/tests/ui/const-generics/non-local-method.stderr new file mode 100644 index 0000000000000..0619570689da3 --- /dev/null +++ b/tests/ui/const-generics/non-local-method.stderr @@ -0,0 +1,9 @@ +error[E0053]: associated function `method` has an incompatible type for const generic parameter + --> $DIR/non-local-method.rs:11:24 + | +LL | fn method() { + | ^^^ expected `i32`, found `u16` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/consts/const-eval/do_not_const_check.rs b/tests/ui/consts/const-eval/do_not_const_check.rs index ced2557bffd19..7ed6ca1491f26 100644 --- a/tests/ui/consts/const-eval/do_not_const_check.rs +++ b/tests/ui/consts/const-eval/do_not_const_check.rs @@ -1,5 +1,17 @@ //! Ensure that we refuse to run a do_not_const_check function, even if the body *would* const-check //! at the moment. + +//@ rustc-env:RUSTC_ICE=0 +//@ failure-status: 101 +//@ normalize-stderr: "note: compiler flags.*\n\n" -> "" +//@ normalize-stderr: "note: rustc.*running on.*" -> "note: rustc {version} running on {platform}" +//@ normalize-stderr: "thread 'rustc'.*panicked.*:\n.*\n" -> "" +//@ normalize-stderr: " +\d{1,}: .*\n" -> "" +//@ normalize-stderr: " + at .*\n" -> "" +//@ normalize-stderr: " +.*omitted.*frames?.*\n" -> "" +//@ normalize-stderr: ".*note: Some details are omitted.*\n" -> "" +//@ normalize-stderr: "(internal compiler error: ).*(compiler/[^:]+):\d+:\d+: " -> "$1$2:LL:CC: " + #![feature(rustc_attrs, intrinsics)] #[rustc_do_not_const_check] diff --git a/tests/ui/consts/const-eval/do_not_const_check.stderr b/tests/ui/consts/const-eval/do_not_const_check.stderr index 7b91d75298e06..7db40e7ab0114 100644 --- a/tests/ui/consts/const-eval/do_not_const_check.stderr +++ b/tests/ui/consts/const-eval/do_not_const_check.stderr @@ -1,17 +1,40 @@ -error[E0080]: calling non-const function `mostly_harmless` - --> $DIR/do_not_const_check.rs:9:5 +error: internal compiler error: compiler/rustc_const_eval/src/const_eval/machine.rs:LL:CC: calling non-const function `mostly_harmless` + --> $DIR/do_not_const_check.rs:21:5 | -LL | const _: () = { LL | mostly_harmless(); - | ^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + | ^^^^^^^^^^^^^^^^^ -error[E0080]: calling non-const function `integer_min::` - --> $DIR/do_not_const_check.rs:22:5 + +stack backtrace: + +note: using internal features is not supported and expected to cause internal compiler errors when used incorrectly + +note: rustc {version} running on {platform} + +query stack during panic: +#0 [eval_to_allocation_raw] const-evaluating + checking `_` +#1 [eval_to_const_value_raw] simplifying constant for the type system `_` +#2 [eval_to_const_value_raw] simplifying constant for the type system `_` +#3 [analysis] running analysis passes on crate `do_not_const_check` +end of query stack +error: internal compiler error: compiler/rustc_const_eval/src/const_eval/machine.rs:LL:CC: calling non-const function `integer_min::` + --> $DIR/do_not_const_check.rs:34:5 | -LL | const _: () = { LL | integer_min(0, 1); - | ^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + | ^^^^^^^^^^^^^^^^^ + + +stack backtrace: + +note: using internal features is not supported and expected to cause internal compiler errors when used incorrectly + +note: rustc {version} running on {platform} +query stack during panic: +#0 [eval_to_allocation_raw] const-evaluating + checking `_` +#1 [eval_to_const_value_raw] simplifying constant for the type system `_` +#2 [eval_to_const_value_raw] simplifying constant for the type system `_` +#3 [analysis] running analysis passes on crate `do_not_const_check` +end of query stack error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_in_pattern/suggest_equality_comparison_instead_of_pattern_matching.stderr b/tests/ui/consts/const_in_pattern/suggest_equality_comparison_instead_of_pattern_matching.stderr index 38440af675feb..8e642de858563 100644 --- a/tests/ui/consts/const_in_pattern/suggest_equality_comparison_instead_of_pattern_matching.stderr +++ b/tests/ui/consts/const_in_pattern/suggest_equality_comparison_instead_of_pattern_matching.stderr @@ -147,6 +147,8 @@ LL | if let V = vec![] {} = note: `Vec<()>` is not usable in patterns | = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details +help: check for equality instead of pattern matching + --> $SRC_DIR/alloc/src/macros.rs:LL:COL error: constant of non-structural type `Vec<()>` in a pattern --> $DIR/suggest_equality_comparison_instead_of_pattern_matching.rs:28:13 diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.rs b/tests/ui/consts/qualif-indirect-mutation-fail.rs index 00c9d4900f5f6..26d251788c3ab 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.rs +++ b/tests/ui/consts/qualif-indirect-mutation-fail.rs @@ -13,26 +13,30 @@ pub const fn f() { let _ = &mut a.1; } -// Mutable borrow of a type with drop impl. -pub const A1: () = { - let mut x = None; //~ ERROR destructor of - let mut y = Some(NotConstDestruct); - let a = &mut x; - let b = &mut y; - std::mem::swap(a, b); - std::mem::forget(y); -}; //~ ERROR calling non-const function `::drop` +// FIXME: we make these associated consts to work around +// . +impl NotConstDestruct { + // Mutable borrow of a type with drop impl. + pub const A1: () = { + let mut x = None; //~ ERROR destructor of + let mut y = Some(NotConstDestruct); + let a = &mut x; + let b = &mut y; + std::mem::swap(a, b); + std::mem::forget(y); + }; -// Mutable borrow of a type with drop impl. -pub const A2: () = { - let mut x = None; - let mut y = Some(NotConstDestruct); - let a = &mut x; - let b = &mut y; - std::mem::swap(a, b); - std::mem::forget(y); - let _z = x; //~ ERROR destructor of -}; //~ ERROR calling non-const function `::drop` + // Mutable borrow of a type with drop impl. + pub const A2: () = { + let mut x = None; + let mut y = Some(NotConstDestruct); + let a = &mut x; + let b = &mut y; + std::mem::swap(a, b); + std::mem::forget(y); + let _z = x; //~ ERROR destructor of + }; +} // Shared borrow of a type that might be !Freeze and Drop. pub const fn g1() { diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr index aef0bed72d892..2301490065d45 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.stderr +++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr @@ -1,46 +1,3 @@ -error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:18:9 - | -LL | let mut x = None; - | ^^^^^ the destructor for this type cannot be evaluated in constants -... -LL | }; - | - value is dropped here - -error[E0080]: calling non-const function `::drop` - --> $DIR/qualif-indirect-mutation-fail.rs:24:1 - | -LL | pub const A1: () = { -... -LL | }; - | ^ evaluation of `A1` failed inside this call - | -note: inside `std::ptr::drop_glue::> - shim(Some(Option))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_glue:: - shim(Some(NotConstDestruct))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL - -error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:34:9 - | -LL | let _z = x; - | ^^ the destructor for this type cannot be evaluated in constants -LL | }; - | - value is dropped here - -error[E0080]: calling non-const function `::drop` - --> $DIR/qualif-indirect-mutation-fail.rs:35:1 - | -LL | pub const A2: () = { -... -LL | }; - | ^ evaluation of `A2` failed inside this call - | -note: inside `std::ptr::drop_glue::> - shim(Some(Option))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `std::ptr::drop_glue:: - shim(Some(NotConstDestruct))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL - error[E0493]: destructor of `(u32, Option)` cannot be evaluated at compile-time --> $DIR/qualif-indirect-mutation-fail.rs:12:9 | @@ -50,8 +7,25 @@ LL | let _ = &mut a.1; LL | } | - value is dropped here +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:21:13 + | +LL | let mut x = None; + | ^^^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error[E0493]: destructor of `Option` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:37:13 + | +LL | let _z = x; + | ^^ the destructor for this type cannot be evaluated in constants +LL | }; + | - value is dropped here + error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:39:9 + --> $DIR/qualif-indirect-mutation-fail.rs:43:9 | LL | let x: Option = None; | ^ the destructor for this type cannot be evaluated in constant functions @@ -60,7 +34,7 @@ LL | } | - value is dropped here error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:47:9 + --> $DIR/qualif-indirect-mutation-fail.rs:51:9 | LL | let _y = x; | ^^ the destructor for this type cannot be evaluated in constant functions @@ -68,7 +42,7 @@ LL | } | - value is dropped here error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:55:9 + --> $DIR/qualif-indirect-mutation-fail.rs:59:9 | LL | let mut y: Option = None; | ^^^^^ the destructor for this type cannot be evaluated in constant functions @@ -77,7 +51,7 @@ LL | } | - value is dropped here error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:52:9 + --> $DIR/qualif-indirect-mutation-fail.rs:56:9 | LL | let mut x: Option = None; | ^^^^^ the destructor for this type cannot be evaluated in constant functions @@ -86,7 +60,7 @@ LL | } | - value is dropped here error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:65:9 + --> $DIR/qualif-indirect-mutation-fail.rs:69:9 | LL | let y: Option = None; | ^ the destructor for this type cannot be evaluated in constant functions @@ -95,7 +69,7 @@ LL | } | - value is dropped here error[E0493]: destructor of `Option` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:62:9 + --> $DIR/qualif-indirect-mutation-fail.rs:66:9 | LL | let x: Option = None; | ^ the destructor for this type cannot be evaluated in constant functions @@ -103,7 +77,6 @@ LL | let x: Option = None; LL | } | - value is dropped here -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0080, E0493. -For more information about an error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/generic-associated-types/const_params_have_right_type.rs b/tests/ui/generic-associated-types/const_params_have_right_type.rs index d2cb12697e423..d3552c3773b1f 100644 --- a/tests/ui/generic-associated-types/const_params_have_right_type.rs +++ b/tests/ui/generic-associated-types/const_params_have_right_type.rs @@ -4,7 +4,7 @@ trait Trait { impl Trait for () { type Foo = u32; - //~^ error: type `Foo` has an incompatible generic parameter for trait + //~^ error: associated type `Foo` has an incompatible type for const generic parameter [E0053] } fn main() {} diff --git a/tests/ui/generic-associated-types/const_params_have_right_type.stderr b/tests/ui/generic-associated-types/const_params_have_right_type.stderr index f477ac3027726..ef81514d8ce90 100644 --- a/tests/ui/generic-associated-types/const_params_have_right_type.stderr +++ b/tests/ui/generic-associated-types/const_params_have_right_type.stderr @@ -1,13 +1,14 @@ -error[E0053]: associated type `Foo` has an incompatible generic parameter for trait `Trait` - --> $DIR/const_params_have_right_type.rs:6:14 +error[E0053]: associated type `Foo` has an incompatible type for const generic parameter + --> $DIR/const_params_have_right_type.rs:6:23 | -LL | trait Trait { -LL | type Foo; - | ----------- expected const parameter of type `u8` -... -LL | impl Trait for () { LL | type Foo = u32; - | ^^^^^^^^^^^^ found const parameter of type `u64` + | ^^^ expected `u8`, found `u64` + | +note: type in trait + --> $DIR/const_params_have_right_type.rs:2:23 + | +LL | type Foo; + | ^^ error: aborting due to 1 previous error diff --git a/tests/ui/generic-const-items/compare-impl-item.rs b/tests/ui/generic-const-items/compare-impl-item.rs index e8a23b5c44bb2..8bf89eb7a0aa4 100644 --- a/tests/ui/generic-const-items/compare-impl-item.rs +++ b/tests/ui/generic-const-items/compare-impl-item.rs @@ -20,7 +20,7 @@ impl

Trait

for () { const C<'a>: &'a str = ""; //~^ ERROR constant `C` has 0 type parameters but its trait declaration has 1 type parameter const D: u16 = N; - //~^ ERROR constant `D` has an incompatible generic parameter for trait `Trait` + //~^ ERROR associated constant `D` has an incompatible type for const generic parameter const E: &'static () = &(); //~^ ERROR lifetime parameters or bounds on associated constant `E` do not match the trait declaration diff --git a/tests/ui/generic-const-items/compare-impl-item.stderr b/tests/ui/generic-const-items/compare-impl-item.stderr index e61a1fdc0cf5a..6577fa8a375fc 100644 --- a/tests/ui/generic-const-items/compare-impl-item.stderr +++ b/tests/ui/generic-const-items/compare-impl-item.stderr @@ -27,18 +27,17 @@ LL | const C: T; LL | const C<'a>: &'a str = ""; | ^^ found 0 type parameters -error[E0053]: associated constant `D` has an incompatible generic parameter for trait `Trait` - --> $DIR/compare-impl-item.rs:22:13 +error[E0053]: associated constant `D` has an incompatible type for const generic parameter + --> $DIR/compare-impl-item.rs:22:22 | -LL | trait Trait

{ -... -LL | const D: usize; - | -------------- expected const parameter of type `usize` -... -LL | impl

Trait

for () { -... LL | const D: u16 = N; - | ^^^^^^^^^^^^ found const parameter of type `u16` + | ^^^ expected `usize`, found `u16` + | +note: type in trait + --> $DIR/compare-impl-item.rs:8:22 + | +LL | const D: usize; + | ^^^^^ error[E0195]: lifetime parameters or bounds on associated constant `E` do not match the trait declaration --> $DIR/compare-impl-item.rs:24:12 diff --git a/tests/ui/pin-ergonomics/pinned-drop-check.stderr b/tests/ui/pin-ergonomics/pinned-drop-check.stderr index 6087d45dd2900..9046ac1f46a8e 100644 --- a/tests/ui/pin-ergonomics/pinned-drop-check.stderr +++ b/tests/ui/pin-ergonomics/pinned-drop-check.stderr @@ -293,36 +293,54 @@ error[E0040]: explicit use of destructor method | LL | Drop::pin_drop(todo!()); | ^^^^^^^^^^^^^^ explicit destructor calls not allowed + | +help: consider using `drop` function + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL error[E0040]: explicit use of destructor method --> $DIR/pinned-drop-check.rs:156:13 | LL | Drop::pin_drop(todo!()); | ^^^^^^^^^^^^^^ explicit destructor calls not allowed + | +help: consider using `drop` function + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL error[E0040]: explicit use of destructor method --> $DIR/pinned-drop-check.rs:168:13 | LL | Drop::drop(todo!()); | ^^^^^^^^^^ explicit destructor calls not allowed + | +help: consider using `drop` function + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL error[E0040]: explicit use of destructor method --> $DIR/pinned-drop-check.rs:173:13 | LL | Drop::drop(todo!()); | ^^^^^^^^^^ explicit destructor calls not allowed + | +help: consider using `drop` function + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL error[E0040]: explicit use of destructor method --> $DIR/pinned-drop-check.rs:183:13 | LL | Drop::drop(todo!()); | ^^^^^^^^^^ explicit destructor calls not allowed + | +help: consider using `drop` function + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL error[E0040]: explicit use of destructor method --> $DIR/pinned-drop-check.rs:184:13 | LL | Drop::pin_drop(todo!()); | ^^^^^^^^^^^^^^ explicit destructor calls not allowed + | +help: consider using `drop` function + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL error: aborting due to 25 previous errors diff --git a/tests/ui/span/coerce-suggestions.rs b/tests/ui/span/coerce-suggestions.rs index 13331a016fcfe..3395013e9910d 100644 --- a/tests/ui/span/coerce-suggestions.rs +++ b/tests/ui/span/coerce-suggestions.rs @@ -2,6 +2,7 @@ fn test(_x: &mut String) {} fn test2(_x: &mut i32) {} +fn test3(_x: *mut String) {} fn main() { let x: usize = String::new(); @@ -11,9 +12,18 @@ fn main() { let y = String::new(); test(&y); //~^ ERROR E0308 + test(&raw const y); + //~^ ERROR E0308 + test(&raw mut y); + //~^ ERROR E0308 test2(&y); //~^ ERROR E0308 let s = &mut String::new(); s = format!("foo"); //~^ ERROR E0308 + let s = String::new(); + test3(&raw const s); + //~^ ERROR E0308 + test3(&s); + //~^ ERROR E0308 } diff --git a/tests/ui/span/coerce-suggestions.stderr b/tests/ui/span/coerce-suggestions.stderr index d0f76a23edc45..5b9049ab6f214 100644 --- a/tests/ui/span/coerce-suggestions.stderr +++ b/tests/ui/span/coerce-suggestions.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/coerce-suggestions.rs:7:20 + --> $DIR/coerce-suggestions.rs:8:20 | LL | let x: usize = String::new(); | ----- ^^^^^^^^^^^^^ expected `usize`, found `String` @@ -7,7 +7,7 @@ LL | let x: usize = String::new(); | expected due to this error[E0308]: mismatched types - --> $DIR/coerce-suggestions.rs:9:19 + --> $DIR/coerce-suggestions.rs:10:19 | LL | let x: &str = String::new(); | ---- ^^^^^^^^^^^^^ expected `&str`, found `String` @@ -20,7 +20,7 @@ LL | let x: &str = &String::new(); | + error[E0308]: mismatched types - --> $DIR/coerce-suggestions.rs:12:10 + --> $DIR/coerce-suggestions.rs:13:10 | LL | test(&y); | ---- ^^ types differ in mutability @@ -34,9 +34,55 @@ note: function defined here | LL | fn test(_x: &mut String) {} | ^^^^ --------------- +help: consider using `&mut` instead + | +LL | test(&mut y); + | +++ error[E0308]: mismatched types - --> $DIR/coerce-suggestions.rs:14:11 + --> $DIR/coerce-suggestions.rs:15:10 + | +LL | test(&raw const y); + | ---- ^^^^^^^^^^^^ expected `&mut String`, found `*const String` + | | + | arguments to this function are incorrect + | + = note: expected mutable reference `&mut String` + found raw pointer `*const String` +note: function defined here + --> $DIR/coerce-suggestions.rs:1:4 + | +LL | fn test(_x: &mut String) {} + | ^^^^ --------------- +help: consider using `&mut` instead + | +LL - test(&raw const y); +LL + test(&mut y); + | + +error[E0308]: mismatched types + --> $DIR/coerce-suggestions.rs:17:10 + | +LL | test(&raw mut y); + | ---- ^^^^^^^^^^ expected `&mut String`, found `*mut String` + | | + | arguments to this function are incorrect + | + = note: expected mutable reference `&mut String` + found raw pointer `*mut String` +note: function defined here + --> $DIR/coerce-suggestions.rs:1:4 + | +LL | fn test(_x: &mut String) {} + | ^^^^ --------------- +help: consider using `&mut` instead + | +LL - test(&raw mut y); +LL + test(&mut y); + | + +error[E0308]: mismatched types + --> $DIR/coerce-suggestions.rs:19:11 | LL | test2(&y); | ----- ^^ types differ in mutability @@ -52,11 +98,52 @@ LL | fn test2(_x: &mut i32) {} | ^^^^^ ------------ error[E0308]: mismatched types - --> $DIR/coerce-suggestions.rs:17:9 + --> $DIR/coerce-suggestions.rs:22:9 | LL | s = format!("foo"); | ^^^^^^^^^^^^^^ expected `&mut String`, found `String` -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/coerce-suggestions.rs:25:11 + | +LL | test3(&raw const s); + | ----- ^^^^^^^^^^^^ types differ in mutability + | | + | arguments to this function are incorrect + | + = note: expected raw pointer `*mut String` + found raw pointer `*const String` +note: function defined here + --> $DIR/coerce-suggestions.rs:5:4 + | +LL | fn test3(_x: *mut String) {} + | ^^^^^ --------------- +help: consider using `&raw mut` instead + | +LL - test3(&raw const s); +LL + test3(&raw mut s); + | + +error[E0308]: mismatched types + --> $DIR/coerce-suggestions.rs:27:11 + | +LL | test3(&s); + | ----- ^^ types differ in mutability + | | + | arguments to this function are incorrect + | + = note: expected raw pointer `*mut String` + found reference `&String` +note: function defined here + --> $DIR/coerce-suggestions.rs:5:4 + | +LL | fn test3(_x: *mut String) {} + | ^^^^^ --------------- +help: consider using `&mut` instead + | +LL | test3(&mut s); + | +++ + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/structs/ice-line-bounds-issue-148684.stderr b/tests/ui/structs/ice-line-bounds-issue-148684.stderr index 700e59504853c..979cfd07da2ea 100644 --- a/tests/ui/structs/ice-line-bounds-issue-148684.stderr +++ b/tests/ui/structs/ice-line-bounds-issue-148684.stderr @@ -11,6 +11,8 @@ LL | A(2, vec![]) | ^^^^^^^^^^^^ | = note: a struct named `A` exists in another namespace +help: use struct literal syntax instead of calling + --> $SRC_DIR/alloc/src/macros.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.rs b/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.rs new file mode 100644 index 0000000000000..b925e6a7745e6 --- /dev/null +++ b/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.rs @@ -0,0 +1,27 @@ +//@compile-flags: -Znext-solver=globally +//@check-fail + +// See issue https://github.com/rust-lang/rust/issues/161882, test makes sure we don't report +// irrelevant and not implemented bounds when we can't proof an obligation. + +struct MyError; + +trait MaybeFallible { + type Error: MaybeError; //~ ERROR: the trait bound `MyError: From<::Error>` is not satisfied +} + +trait MaybeError: Sized +where + MyError: From, +{ + type ComposeWithOther: MaybeError; //~ ERROR: the trait bound `MyError: From<::ComposeWithOther>` is not satisfied +} + +fn compose() -> Result<(), ()> +where + ::ComposeWithOther: From, //~ ERROR: the trait bound `MyError: From<::Error>` is not satisfied +{ + todo!() +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.stderr b/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.stderr new file mode 100644 index 0000000000000..2dd3f4f9a945f --- /dev/null +++ b/tests/ui/traits/next-solver/confusing-diagnostic-due-to-best-obligation-visitor.stderr @@ -0,0 +1,64 @@ +error[E0277]: the trait bound `MyError: From<::Error>` is not satisfied + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:22:49 + | +LL | ::ComposeWithOther: From, + | ^^^^^^^ unsatisfied trait bound + | +help: the trait `From<::Error>` is not implemented for `MyError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:7:1 + | +LL | struct MyError; + | ^^^^^^^^^^^^^^ +note: required by a bound in `MaybeError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:15:14 + | +LL | trait MaybeError: Sized +LL | where +LL | MyError: From, + | ^^^^^^^^^^ required by this bound in `MaybeError` +help: consider extending the `where` clause, but there might be an alternative better way to express this requirement + | +LL | ::ComposeWithOther: From, MyError: From<::Error> + | ++++++++++++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `MyError: From<::Error>` is not satisfied + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:10:17 + | +LL | type Error: MaybeError; + | ^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `From<::Error>` is not implemented for `MyError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:7:1 + | +LL | struct MyError; + | ^^^^^^^^^^^^^^ +note: required by a bound in `MaybeError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:15:14 + | +LL | trait MaybeError: Sized +LL | where +LL | MyError: From, + | ^^^^^^^^^^ required by this bound in `MaybeError` + +error[E0277]: the trait bound `MyError: From<::ComposeWithOther>` is not satisfied + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:17:28 + | +LL | type ComposeWithOther: MaybeError; + | ^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `From<::ComposeWithOther>` is not implemented for `MyError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:7:1 + | +LL | struct MyError; + | ^^^^^^^^^^^^^^ +note: required by a bound in `MaybeError` + --> $DIR/confusing-diagnostic-due-to-best-obligation-visitor.rs:15:14 + | +LL | trait MaybeError: Sized +LL | where +LL | MyError: From, + | ^^^^^^^^^^ required by this bound in `MaybeError` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`.