|
1 | 1 | //! Concrete error types for all operations which may be invalid in a certain const context. |
2 | 2 |
|
3 | 3 | use hir::{ConstContext, LangItem}; |
4 | | -use rustc_errors::Diag; |
5 | 4 | use rustc_errors::codes::*; |
| 5 | +use rustc_errors::{Applicability, Diag, MultiSpan}; |
6 | 6 | use rustc_hir as hir; |
| 7 | +use rustc_hir::def::DefKind; |
7 | 8 | use rustc_hir::def_id::DefId; |
8 | 9 | use rustc_infer::infer::TyCtxtInferExt; |
9 | 10 | use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; |
@@ -355,13 +356,58 @@ fn build_error_for_const_call<'tcx>( |
355 | 356 | non_or_conditionally, |
356 | 357 | }) |
357 | 358 | } |
358 | | - _ => ccx.dcx().create_err(errors::NonConstFnCall { |
359 | | - span, |
360 | | - def_descr: ccx.tcx.def_descr(callee), |
361 | | - def_path_str: ccx.tcx.def_path_str_with_args(callee, args), |
362 | | - kind: ccx.const_kind(), |
363 | | - non_or_conditionally, |
364 | | - }), |
| 359 | + _ => { |
| 360 | + let def_descr = ccx.tcx.def_descr(callee); |
| 361 | + let mut err = ccx.dcx().create_err(errors::NonConstFnCall { |
| 362 | + span, |
| 363 | + def_descr, |
| 364 | + def_path_str: ccx.tcx.def_path_str_with_args(callee, args), |
| 365 | + kind: ccx.const_kind(), |
| 366 | + non_or_conditionally, |
| 367 | + }); |
| 368 | + let def_kind = ccx.tcx.def_kind(callee); |
| 369 | + if let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn = def_kind { |
| 370 | + let parent = ccx.tcx.parent(callee); |
| 371 | + if let DefKind::Trait = ccx.tcx.def_kind(parent) |
| 372 | + && !ccx.tcx.is_const_trait(parent) |
| 373 | + { |
| 374 | + let assoc_span = ccx.tcx.def_span(callee); |
| 375 | + let assoc_name = ccx.tcx.item_name(callee); |
| 376 | + let mut span: MultiSpan = ccx.tcx.def_span(parent).into(); |
| 377 | + span.push_span_label(assoc_span, format!("this {def_descr} is not const")); |
| 378 | + let trait_descr = ccx.tcx.def_descr(parent); |
| 379 | + let trait_span = ccx.tcx.def_span(parent); |
| 380 | + let trait_name = ccx.tcx.item_name(parent); |
| 381 | + span.push_span_label(trait_span, format!("this {trait_descr} is not const")); |
| 382 | + err.span_note( |
| 383 | + span, |
| 384 | + format!( |
| 385 | + "{def_descr} `{assoc_name}` is not const because {trait_descr} \ |
| 386 | + `{trait_name}` is not const", |
| 387 | + ), |
| 388 | + ); |
| 389 | + let indentation = ccx |
| 390 | + .tcx |
| 391 | + .sess |
| 392 | + .source_map() |
| 393 | + .indentation_before(trait_span) |
| 394 | + .unwrap_or_default(); |
| 395 | + err.span_suggestion_verbose( |
| 396 | + trait_span.shrink_to_lo(), |
| 397 | + format!("consider making trait `{trait_name}` const"), |
| 398 | + format!("#[const_trait]\n{indentation}"), |
| 399 | + Applicability::MachineApplicable, |
| 400 | + ); |
| 401 | + } |
| 402 | + } else if ccx.tcx.constness(callee) != hir::Constness::Const { |
| 403 | + let name = ccx.tcx.item_name(callee); |
| 404 | + err.span_note( |
| 405 | + ccx.tcx.def_span(callee), |
| 406 | + format!("{def_descr} `{name}` is not const"), |
| 407 | + ); |
| 408 | + } |
| 409 | + err |
| 410 | + } |
365 | 411 | }; |
366 | 412 |
|
367 | 413 | err.note(format!( |
|
0 commit comments