Auto merge of #88371 - Manishearth:rollup-pkkjsme, r=Manishearth
Rollup of 11 pull requests Successful merges: - #87832 (Fix debugger stepping behavior with `match` expressions) - #88123 (Make spans for tuple patterns in E0023 more precise) - #88215 (Reland #83738: "rustdoc: Don't load all extern crates unconditionally") - #88216 (Don't stabilize creation of TryReserveError instances) - #88270 (Handle type ascription type ops in NLL HRTB diagnostics) - #88289 (Fixes for LLVM change 0f45c16f2caa7c035e5c3edd40af9e0d51ad6ba7) - #88320 (type_implements_trait consider obligation failure on overflow) - #88332 (Add argument types tait tests) - #88340 (Add `c_size_t` and `c_ssize_t` to `std::os::raw`.) - #88346 (Revert "Add type of a let tait test impl trait straight in let") - #88348 (Add field types tait tests) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
d5cd3205fd
140 changed files with 2390 additions and 711 deletions
|
@ -3183,6 +3183,20 @@ pub enum Node<'hir> {
|
|||
}
|
||||
|
||||
impl<'hir> Node<'hir> {
|
||||
/// Get the identifier of this `Node`, if applicable.
|
||||
///
|
||||
/// # Edge cases
|
||||
///
|
||||
/// Calling `.ident()` on a [`Node::Ctor`] will return `None`
|
||||
/// because `Ctor`s do not have identifiers themselves.
|
||||
/// Instead, call `.ident()` on the parent struct/variant, like so:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// ctor
|
||||
/// .ctor_hir_id()
|
||||
/// .and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
|
||||
/// .and_then(|parent| parent.ident())
|
||||
/// ```
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
match self {
|
||||
Node::TraitItem(TraitItem { ident, .. })
|
||||
|
@ -3191,8 +3205,25 @@ impl<'hir> Node<'hir> {
|
|||
| Node::Field(FieldDef { ident, .. })
|
||||
| Node::Variant(Variant { ident, .. })
|
||||
| Node::MacroDef(MacroDef { ident, .. })
|
||||
| Node::Item(Item { ident, .. }) => Some(*ident),
|
||||
_ => None,
|
||||
| Node::Item(Item { ident, .. })
|
||||
| Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
|
||||
Node::Lifetime(lt) => Some(lt.name.ident()),
|
||||
Node::GenericParam(p) => Some(p.name.ident()),
|
||||
Node::Param(..)
|
||||
| Node::AnonConst(..)
|
||||
| Node::Expr(..)
|
||||
| Node::Stmt(..)
|
||||
| Node::Block(..)
|
||||
| Node::Ctor(..)
|
||||
| Node::Pat(..)
|
||||
| Node::Binding(..)
|
||||
| Node::Arm(..)
|
||||
| Node::Local(..)
|
||||
| Node::Visibility(..)
|
||||
| Node::Crate(..)
|
||||
| Node::Ty(..)
|
||||
| Node::TraitRef(..)
|
||||
| Node::Infer(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -270,34 +270,30 @@ extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index,
|
|||
LLVMRustAttribute RustAttr) {
|
||||
Function *A = unwrap<Function>(Fn);
|
||||
Attribute Attr = Attribute::get(A->getContext(), fromRust(RustAttr));
|
||||
AttrBuilder B(Attr);
|
||||
A->addAttributes(Index, B);
|
||||
A->addAttribute(Index, Attr);
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustAddAlignmentAttr(LLVMValueRef Fn,
|
||||
unsigned Index,
|
||||
uint32_t Bytes) {
|
||||
Function *A = unwrap<Function>(Fn);
|
||||
AttrBuilder B;
|
||||
B.addAlignmentAttr(Bytes);
|
||||
A->addAttributes(Index, B);
|
||||
A->addAttribute(Index, Attribute::getWithAlignment(
|
||||
A->getContext(), llvm::Align(Bytes)));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index,
|
||||
uint64_t Bytes) {
|
||||
Function *A = unwrap<Function>(Fn);
|
||||
AttrBuilder B;
|
||||
B.addDereferenceableAttr(Bytes);
|
||||
A->addAttributes(Index, B);
|
||||
A->addAttribute(Index, Attribute::getWithDereferenceableBytes(A->getContext(),
|
||||
Bytes));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustAddDereferenceableOrNullAttr(LLVMValueRef Fn,
|
||||
unsigned Index,
|
||||
uint64_t Bytes) {
|
||||
Function *A = unwrap<Function>(Fn);
|
||||
AttrBuilder B;
|
||||
B.addDereferenceableOrNullAttr(Bytes);
|
||||
A->addAttributes(Index, B);
|
||||
A->addAttribute(Index, Attribute::getWithDereferenceableOrNullBytes(
|
||||
A->getContext(), Bytes));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustAddByValAttr(LLVMValueRef Fn, unsigned Index,
|
||||
|
@ -323,9 +319,8 @@ extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn,
|
|||
const char *Name,
|
||||
const char *Value) {
|
||||
Function *F = unwrap<Function>(Fn);
|
||||
AttrBuilder B;
|
||||
B.addAttribute(Name, Value);
|
||||
F->addAttributes(Index, B);
|
||||
F->addAttribute(Index, Attribute::get(
|
||||
F->getContext(), StringRef(Name), StringRef(Value)));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn,
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
|||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::type_op;
|
||||
use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
|
||||
use rustc_traits::type_op_prove_predicate_with_span;
|
||||
use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
|
||||
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
@ -104,10 +104,11 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'t
|
|||
impl<'tcx> ToUniverseInfo<'tcx>
|
||||
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
|
||||
{
|
||||
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
// Ascribe user type isn't usually called on types that have different
|
||||
// bound regions.
|
||||
UniverseInfo::other()
|
||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
|
||||
canonical_query: self,
|
||||
base_universe,
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,6 +268,37 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
struct AscribeUserTypeQuery<'tcx> {
|
||||
canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
|
||||
base_universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
|
||||
// and is only the fallback when the nice error fails. Consider improving this some more.
|
||||
tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
|
||||
}
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex {
|
||||
self.base_universe
|
||||
}
|
||||
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
|
||||
type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?;
|
||||
try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
|
|
|
@ -21,7 +21,7 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::thir::{self, *};
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{BytePos, Pos, Span};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
|
@ -143,8 +143,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let mut candidates =
|
||||
arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
|
||||
|
||||
let fake_borrow_temps =
|
||||
self.lower_match_tree(block, scrutinee_span, match_has_guard, &mut candidates);
|
||||
let match_start_span = span.shrink_to_lo().to(scrutinee.span);
|
||||
|
||||
let fake_borrow_temps = self.lower_match_tree(
|
||||
block,
|
||||
scrutinee_span,
|
||||
match_start_span,
|
||||
match_has_guard,
|
||||
&mut candidates,
|
||||
);
|
||||
|
||||
self.lower_match_arms(
|
||||
destination,
|
||||
|
@ -224,6 +231,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
&mut self,
|
||||
block: BasicBlock,
|
||||
scrutinee_span: Span,
|
||||
match_start_span: Span,
|
||||
match_has_guard: bool,
|
||||
candidates: &mut [&mut Candidate<'pat, 'tcx>],
|
||||
) -> Vec<(Place<'tcx>, Local)> {
|
||||
|
@ -236,7 +244,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
// This will generate code to test scrutinee_place and
|
||||
// branch to the appropriate arm block
|
||||
self.match_candidates(scrutinee_span, block, &mut otherwise, candidates, &mut fake_borrows);
|
||||
self.match_candidates(
|
||||
match_start_span,
|
||||
scrutinee_span,
|
||||
block,
|
||||
&mut otherwise,
|
||||
candidates,
|
||||
&mut fake_borrows,
|
||||
);
|
||||
|
||||
if let Some(otherwise_block) = otherwise {
|
||||
// See the doc comment on `match_candidates` for why we may have an
|
||||
|
@ -339,8 +354,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// all the arm blocks will rejoin here
|
||||
let end_block = self.cfg.start_new_block();
|
||||
|
||||
let end_brace = self.source_info(
|
||||
outer_source_info.span.with_lo(outer_source_info.span.hi() - BytePos::from_usize(1)),
|
||||
);
|
||||
for arm_block in arm_end_blocks {
|
||||
self.cfg.goto(unpack!(arm_block), outer_source_info, end_block);
|
||||
let block = &self.cfg.basic_blocks[arm_block.0];
|
||||
let last_location = block.statements.last().map(|s| s.source_info);
|
||||
|
||||
self.cfg.goto(unpack!(arm_block), last_location.unwrap_or(end_brace), end_block);
|
||||
}
|
||||
|
||||
self.source_scope = outer_source_info.scope;
|
||||
|
@ -533,8 +554,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
set_match_place: bool,
|
||||
) -> BlockAnd<()> {
|
||||
let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false);
|
||||
let fake_borrow_temps =
|
||||
self.lower_match_tree(block, irrefutable_pat.span, false, &mut [&mut candidate]);
|
||||
let fake_borrow_temps = self.lower_match_tree(
|
||||
block,
|
||||
irrefutable_pat.span,
|
||||
irrefutable_pat.span,
|
||||
false,
|
||||
&mut [&mut candidate],
|
||||
);
|
||||
// For matches and function arguments, the place that is being matched
|
||||
// can be set when creating the variables. But the place for
|
||||
// let PATTERN = ... might not even exist until we do the assignment.
|
||||
|
@ -993,6 +1019,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
fn match_candidates<'pat>(
|
||||
&mut self,
|
||||
span: Span,
|
||||
scrutinee_span: Span,
|
||||
start_block: BasicBlock,
|
||||
otherwise_block: &mut Option<BasicBlock>,
|
||||
candidates: &mut [&mut Candidate<'pat, 'tcx>],
|
||||
|
@ -1022,6 +1049,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
self.match_simplified_candidates(
|
||||
span,
|
||||
scrutinee_span,
|
||||
start_block,
|
||||
otherwise_block,
|
||||
&mut *new_candidates,
|
||||
|
@ -1030,6 +1058,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
} else {
|
||||
self.match_simplified_candidates(
|
||||
span,
|
||||
scrutinee_span,
|
||||
start_block,
|
||||
otherwise_block,
|
||||
candidates,
|
||||
|
@ -1042,6 +1071,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
fn match_simplified_candidates(
|
||||
&mut self,
|
||||
span: Span,
|
||||
scrutinee_span: Span,
|
||||
start_block: BasicBlock,
|
||||
otherwise_block: &mut Option<BasicBlock>,
|
||||
candidates: &mut [&mut Candidate<'_, 'tcx>],
|
||||
|
@ -1087,6 +1117,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// Test for the remaining candidates.
|
||||
self.test_candidates_with_or(
|
||||
span,
|
||||
scrutinee_span,
|
||||
unmatched_candidates,
|
||||
block,
|
||||
otherwise_block,
|
||||
|
@ -1257,6 +1288,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
fn test_candidates_with_or(
|
||||
&mut self,
|
||||
span: Span,
|
||||
scrutinee_span: Span,
|
||||
candidates: &mut [&mut Candidate<'_, 'tcx>],
|
||||
block: BasicBlock,
|
||||
otherwise_block: &mut Option<BasicBlock>,
|
||||
|
@ -1269,7 +1301,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
match *first_candidate.match_pairs[0].pattern.kind {
|
||||
PatKind::Or { .. } => (),
|
||||
_ => {
|
||||
self.test_candidates(span, candidates, block, otherwise_block, fake_borrows);
|
||||
self.test_candidates(
|
||||
span,
|
||||
scrutinee_span,
|
||||
candidates,
|
||||
block,
|
||||
otherwise_block,
|
||||
fake_borrows,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1302,6 +1341,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
self.match_candidates(
|
||||
span,
|
||||
scrutinee_span,
|
||||
remainder_start,
|
||||
otherwise_block,
|
||||
remaining_candidates,
|
||||
|
@ -1330,6 +1370,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
otherwise
|
||||
};
|
||||
self.match_candidates(
|
||||
or_span,
|
||||
or_span,
|
||||
candidate.pre_binding_block.unwrap(),
|
||||
otherwise,
|
||||
|
@ -1497,6 +1538,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
fn test_candidates<'pat, 'b, 'c>(
|
||||
&mut self,
|
||||
span: Span,
|
||||
scrutinee_span: Span,
|
||||
mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
|
||||
block: BasicBlock,
|
||||
otherwise_block: &mut Option<BasicBlock>,
|
||||
|
@ -1591,6 +1633,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let candidate_start = this.cfg.start_new_block();
|
||||
this.match_candidates(
|
||||
span,
|
||||
scrutinee_span,
|
||||
candidate_start,
|
||||
remainder_start,
|
||||
&mut *candidates,
|
||||
|
@ -1607,6 +1650,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let remainder_start = remainder_start.unwrap_or_else(|| this.cfg.start_new_block());
|
||||
this.match_candidates(
|
||||
span,
|
||||
scrutinee_span,
|
||||
remainder_start,
|
||||
otherwise_block,
|
||||
candidates,
|
||||
|
@ -1617,7 +1661,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
target_blocks
|
||||
};
|
||||
|
||||
self.perform_test(block, match_place, &test, make_target_blocks);
|
||||
self.perform_test(span, scrutinee_span, block, match_place, &test, make_target_blocks);
|
||||
}
|
||||
|
||||
/// Determine the fake borrows that are needed from a set of places that
|
||||
|
@ -1713,6 +1757,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let fake_borrow_temps = self.lower_match_tree(
|
||||
block,
|
||||
pat.span,
|
||||
pat.span,
|
||||
false,
|
||||
&mut [&mut guard_candidate, &mut otherwise_candidate],
|
||||
);
|
||||
|
|
|
@ -19,6 +19,7 @@ use rustc_middle::ty::util::IntTypeExt;
|
|||
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::VariantIdx;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
@ -151,6 +152,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
pub(super) fn perform_test(
|
||||
&mut self,
|
||||
match_start_span: Span,
|
||||
scrutinee_span: Span,
|
||||
block: BasicBlock,
|
||||
place_builder: PlaceBuilder<'tcx>,
|
||||
test: &Test<'tcx>,
|
||||
|
@ -206,10 +209,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
debug!("num_enum_variants: {}, variants: {:?}", num_enum_variants, variants);
|
||||
let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
|
||||
let discr = self.temp(discr_ty, test.span);
|
||||
self.cfg.push_assign(block, source_info, discr, Rvalue::Discriminant(place));
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
self.source_info(scrutinee_span),
|
||||
discr,
|
||||
Rvalue::Discriminant(place),
|
||||
);
|
||||
self.cfg.terminate(
|
||||
block,
|
||||
source_info,
|
||||
self.source_info(match_start_span),
|
||||
TerminatorKind::SwitchInt {
|
||||
discr: Operand::Move(discr),
|
||||
switch_ty: discr_ty,
|
||||
|
@ -246,7 +254,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
targets: switch_targets,
|
||||
}
|
||||
};
|
||||
self.cfg.terminate(block, source_info, terminator);
|
||||
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
|
||||
}
|
||||
|
||||
TestKind::Eq { value, ty } => {
|
||||
|
|
|
@ -44,6 +44,10 @@ pub trait InferCtxtExt<'tcx> {
|
|||
/// - the self type
|
||||
/// - the *other* type parameters of the trait, excluding the self-type
|
||||
/// - the parameter environment
|
||||
///
|
||||
/// Invokes `evaluate_obligation`, so in the event that evaluating
|
||||
/// `Ty: Trait` causes overflow, EvaluatedToRecur (or EvaluatedToUnknown)
|
||||
/// will be returned.
|
||||
fn type_implements_trait(
|
||||
&self,
|
||||
trait_def_id: DefId,
|
||||
|
@ -117,7 +121,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
|||
recursion_depth: 0,
|
||||
predicate: trait_ref.without_const().to_predicate(self.tcx),
|
||||
};
|
||||
self.evaluate_obligation_no_overflow(&obligation)
|
||||
self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ mod normalize_erasing_regions;
|
|||
mod normalize_projection_ty;
|
||||
mod type_op;
|
||||
|
||||
pub use type_op::type_op_prove_predicate_with_span;
|
||||
pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
|
||||
|
||||
use rustc_middle::ty::query::Providers;
|
||||
|
||||
|
|
|
@ -40,20 +40,30 @@ fn type_op_ascribe_user_type<'tcx>(
|
|||
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
|
||||
let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
|
||||
|
||||
debug!(
|
||||
"type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
|
||||
mir_ty, def_id, user_substs
|
||||
);
|
||||
|
||||
let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
|
||||
cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?;
|
||||
|
||||
Ok(())
|
||||
type_op_ascribe_user_type_with_span(infcx, fulfill_cx, key, None)
|
||||
})
|
||||
}
|
||||
|
||||
/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
|
||||
/// this query can be re-run to better track the span of the obligation cause, and improve the error
|
||||
/// message. Do not call directly unless you're in that very specific context.
|
||||
pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>(
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
|
||||
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
|
||||
span: Option<Span>,
|
||||
) -> Result<(), NoSolution> {
|
||||
let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
|
||||
debug!(
|
||||
"type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
|
||||
mir_ty, def_id, user_substs
|
||||
);
|
||||
|
||||
let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
|
||||
cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs, span)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct AscribeUserTypeCx<'me, 'tcx> {
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
|
@ -85,10 +95,15 @@ impl AscribeUserTypeCx<'me, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn prove_predicate(&mut self, predicate: Predicate<'tcx>) {
|
||||
fn prove_predicate(&mut self, predicate: Predicate<'tcx>, span: Option<Span>) {
|
||||
let cause = if let Some(span) = span {
|
||||
ObligationCause::dummy_with_span(span)
|
||||
} else {
|
||||
ObligationCause::dummy()
|
||||
};
|
||||
self.fulfill_cx.register_predicate_obligation(
|
||||
self.infcx,
|
||||
Obligation::new(ObligationCause::dummy(), self.param_env, predicate),
|
||||
Obligation::new(cause, self.param_env, predicate),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -108,6 +123,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
|
|||
mir_ty: Ty<'tcx>,
|
||||
def_id: DefId,
|
||||
user_substs: UserSubsts<'tcx>,
|
||||
span: Option<Span>,
|
||||
) -> Result<(), NoSolution> {
|
||||
let UserSubsts { user_self_ty, substs } = user_substs;
|
||||
let tcx = self.tcx();
|
||||
|
@ -129,7 +145,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
|
|||
debug!(?instantiated_predicates.predicates);
|
||||
for instantiated_predicate in instantiated_predicates.predicates {
|
||||
let instantiated_predicate = self.normalize(instantiated_predicate);
|
||||
self.prove_predicate(instantiated_predicate);
|
||||
self.prove_predicate(instantiated_predicate, span);
|
||||
}
|
||||
|
||||
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
|
||||
|
@ -141,6 +157,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
|
|||
|
||||
self.prove_predicate(
|
||||
ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -155,7 +172,10 @@ impl AscribeUserTypeCx<'me, 'tcx> {
|
|||
// them? This would only be relevant if some input
|
||||
// type were ill-formed but did not appear in `ty`,
|
||||
// which...could happen with normalization...
|
||||
self.prove_predicate(ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()));
|
||||
self.prove_predicate(
|
||||
ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
|
||||
span,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,7 +223,18 @@ fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
|
|||
}
|
||||
|
||||
fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
|
||||
tcx.hir().get_if_local(def_id).and_then(|node| node.ident()).map(|ident| ident.span)
|
||||
tcx.hir()
|
||||
.get_if_local(def_id)
|
||||
.and_then(|node| match node {
|
||||
// A `Ctor` doesn't have an identifier itself, but its parent
|
||||
// struct/variant does. Compare with `hir::Map::opt_span`.
|
||||
hir::Node::Ctor(ctor) => ctor
|
||||
.ctor_hir_id()
|
||||
.and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
|
||||
.and_then(|parent| parent.ident()),
|
||||
_ => node.ident(),
|
||||
})
|
||||
.map(|ident| ident.span)
|
||||
}
|
||||
|
||||
/// If the given `DefId` describes an item belonging to a trait,
|
||||
|
|
|
@ -15,7 +15,7 @@ use rustc_span::hygiene::DesugaringKind;
|
|||
use rustc_span::lev_distance::find_best_match_for_name;
|
||||
use rustc_span::source_map::{Span, Spanned};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{BytePos, DUMMY_SP};
|
||||
use rustc_span::{BytePos, MultiSpan, DUMMY_SP};
|
||||
use rustc_trait_selection::autoderef::Autoderef;
|
||||
use rustc_trait_selection::traits::{ObligationCause, Pattern};
|
||||
use ty::VariantDef;
|
||||
|
@ -990,10 +990,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) {
|
||||
let subpats_ending = pluralize!(subpats.len());
|
||||
let fields_ending = pluralize!(fields.len());
|
||||
|
||||
let subpat_spans = if subpats.is_empty() {
|
||||
vec![pat_span]
|
||||
} else {
|
||||
subpats.iter().map(|p| p.span).collect()
|
||||
};
|
||||
let last_subpat_span = *subpat_spans.last().unwrap();
|
||||
let res_span = self.tcx.def_span(res.def_id());
|
||||
let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
|
||||
let field_def_spans = if fields.is_empty() {
|
||||
vec![res_span]
|
||||
} else {
|
||||
fields.iter().map(|f| f.ident.span).collect()
|
||||
};
|
||||
let last_field_def_span = *field_def_spans.last().unwrap();
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
pat_span,
|
||||
MultiSpan::from_spans(subpat_spans.clone()),
|
||||
E0023,
|
||||
"this pattern has {} field{}, but the corresponding {} has {} field{}",
|
||||
subpats.len(),
|
||||
|
@ -1003,10 +1018,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fields_ending,
|
||||
);
|
||||
err.span_label(
|
||||
pat_span,
|
||||
format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len(),),
|
||||
)
|
||||
.span_label(res_span, format!("{} defined here", res.descr()));
|
||||
last_subpat_span,
|
||||
&format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
|
||||
);
|
||||
if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
|
||||
err.span_label(qpath.span(), "");
|
||||
}
|
||||
if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) {
|
||||
err.span_label(def_ident_span, format!("{} defined here", res.descr()));
|
||||
}
|
||||
for span in &field_def_spans[..field_def_spans.len() - 1] {
|
||||
err.span_label(*span, "");
|
||||
}
|
||||
err.span_label(
|
||||
last_field_def_span,
|
||||
&format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
|
||||
);
|
||||
|
||||
// Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
|
||||
// More generally, the expected type wants a tuple variant with one field of an
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue