Support HIR wf checking for function signatures
During function type-checking, we normalize any associated types in the function signature (argument types + return type), and then create WF obligations for each of the normalized types. The HIR wf code does not currently support this case, so any errors that we get have imprecise spans. This commit extends `ObligationCauseCode::WellFormed` to support recording a function parameter, allowing us to get the corresponding HIR type if an error occurs. Function typechecking is modified to pass this information during signature normalization and WF checking. The resulting code is fairly verbose, due to the fact that we can no longer normalize the entire signature with a single function call. As part of the refactoring, we now perform HIR-based WF checking for several other 'typed items' (statics, consts, and inherent impls). As a result, WF and projection errors in a function signature now have a precise span, which points directly at the responsible type. If a function signature is constructed via a macro, this will allow the error message to point at the code 'most responsible' for the error (e.g. a user-supplied macro argument).
This commit is contained in:
parent
da7d405357
commit
db0324ebb2
28 changed files with 240 additions and 91 deletions
|
@ -29,7 +29,10 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
|
|||
Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
|
||||
| Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. })
|
||||
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl),
|
||||
Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. }) => Some(fn_decl),
|
||||
Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. })
|
||||
| Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => {
|
||||
Some(fn_decl)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1722,7 +1722,7 @@ rustc_queries! {
|
|||
/// span) for an *existing* error. Therefore, it is best-effort, and may never handle
|
||||
/// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine,
|
||||
/// because the `ty::Ty`-based wfcheck is always run.
|
||||
query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, hir::HirId)) -> Option<traits::ObligationCause<'tcx>> {
|
||||
query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option<traits::ObligationCause<'tcx>> {
|
||||
eval_always
|
||||
no_hash
|
||||
desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 }
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::ty::{self, AdtKind, Ty, TyCtxt};
|
|||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::Constness;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
@ -327,17 +327,39 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
/// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y`
|
||||
OpaqueType,
|
||||
|
||||
/// Well-formed checking. If a `HirId` is provided,
|
||||
/// it is used to perform HIR-based wf checking if an error
|
||||
/// occurs, in order to generate a more precise error message.
|
||||
/// Well-formed checking. If a `WellFormedLoc` is provided,
|
||||
/// then it will be used to eprform HIR-based wf checking
|
||||
/// after an error occurs, in order to generate a more precise error span.
|
||||
/// This is purely for diagnostic purposes - it is always
|
||||
/// correct to use `MiscObligation` instead
|
||||
WellFormed(Option<hir::HirId>),
|
||||
/// correct to use `MiscObligation` instead, or to specify
|
||||
/// `WellFormed(None)`
|
||||
WellFormed(Option<WellFormedLoc>),
|
||||
|
||||
/// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against.
|
||||
MatchImpl(Lrc<ObligationCauseCode<'tcx>>, DefId),
|
||||
}
|
||||
|
||||
/// The 'location' at which we try to perform HIR-based wf checking.
|
||||
/// This information is used to obtain an `hir::Ty`, which
|
||||
/// we can walk in order to obtain precise spans for any
|
||||
/// 'nested' types (e.g. `Foo` in `Option<Foo>`).
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||
pub enum WellFormedLoc {
|
||||
/// Use the type of the provided definition.
|
||||
Ty(LocalDefId),
|
||||
/// Use the type of the parameter of the provided function.
|
||||
/// We cannot use `hir::Param`, since the function may
|
||||
/// not have a body (e.g. a trait method definition)
|
||||
Param {
|
||||
/// The function to lookup the parameter in
|
||||
function: LocalDefId,
|
||||
/// The index of the parameter to use.
|
||||
/// Parameters are indexed from 0, with the return type
|
||||
/// being the last 'parameter'
|
||||
param_idx: u16,
|
||||
},
|
||||
}
|
||||
|
||||
impl ObligationCauseCode<'_> {
|
||||
// Return the base obligation, ignoring derived obligations.
|
||||
pub fn peel_derives(&self) -> &Self {
|
||||
|
|
|
@ -1682,7 +1682,7 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable
|
|||
// This is the impl for `&'a InternalSubsts<'a>`.
|
||||
nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>}
|
||||
|
||||
CloneLiftImpls! { for<'tcx> { Constness, } }
|
||||
CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } }
|
||||
|
||||
pub mod tls {
|
||||
use super::{ptr_eq, GlobalCtxt, TyCtxt};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue