Format all the let chains in compiler
This commit is contained in:
parent
2763ca50da
commit
b2d2184ede
206 changed files with 3120 additions and 2228 deletions
|
@ -60,9 +60,7 @@ impl<'a> DescriptionCtx<'a> {
|
|||
let span = Some(tcx.def_span(scope));
|
||||
(span, "defined_here", String::new())
|
||||
}
|
||||
_ => {
|
||||
(Some(tcx.def_span(scope)), "defined_here_reg", region.to_string())
|
||||
}
|
||||
_ => (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,8 +227,10 @@ fn msg_span_from_named_region<'tcx>(
|
|||
let scope = region.free_region_binding_scope(tcx).expect_local();
|
||||
match fr.bound_region {
|
||||
ty::BoundRegionKind::BrNamed(_, name) => {
|
||||
let span = if let Some(param) =
|
||||
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
|
||||
let span = if let Some(param) = tcx
|
||||
.hir()
|
||||
.get_generics(scope)
|
||||
.and_then(|generics| generics.get_named(name))
|
||||
{
|
||||
param.span
|
||||
} else {
|
||||
|
@ -243,7 +245,7 @@ fn msg_span_from_named_region<'tcx>(
|
|||
}
|
||||
ty::BrAnon => (
|
||||
"the anonymous lifetime as defined here".to_string(),
|
||||
Some(tcx.def_span(scope))
|
||||
Some(tcx.def_span(scope)),
|
||||
),
|
||||
_ => (
|
||||
format!("the lifetime `{region}` as defined here"),
|
||||
|
@ -715,13 +717,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
&& let ty::Adt(def, args) = ty.kind()
|
||||
&& Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
|
||||
{
|
||||
err.span_label(span, format!("this is an iterator with items of type `{}`", args.type_at(0)));
|
||||
err.span_label(
|
||||
span,
|
||||
format!("this is an iterator with items of type `{}`", args.type_at(0)),
|
||||
);
|
||||
} else {
|
||||
err.span_label(span, format!("this expression has type `{ty}`"));
|
||||
}
|
||||
err.span_label(span, format!("this expression has type `{ty}`"));
|
||||
}
|
||||
}
|
||||
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
|
||||
&& ty.is_box() && ty.boxed_ty() == found
|
||||
&& ty.is_box()
|
||||
&& ty.boxed_ty() == found
|
||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
{
|
||||
err.span_suggestion(
|
||||
|
@ -743,9 +749,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
|
||||
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
|
||||
let arg_expr = args.first().expect("try desugaring call w/out arg");
|
||||
self.typeck_results.as_ref().and_then(|typeck_results| {
|
||||
typeck_results.expr_ty_opt(arg_expr)
|
||||
})
|
||||
self.typeck_results
|
||||
.as_ref()
|
||||
.and_then(|typeck_results| typeck_results.expr_ty_opt(arg_expr))
|
||||
} else {
|
||||
bug!("try desugaring w/out call expr as scrutinee");
|
||||
};
|
||||
|
@ -763,7 +769,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
arm_block_id,
|
||||
arm_span,
|
||||
|
@ -782,9 +788,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
|
||||
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
|
||||
let arg_expr = args.first().expect("try desugaring call w/out arg");
|
||||
self.typeck_results.as_ref().and_then(|typeck_results| {
|
||||
typeck_results.expr_ty_opt(arg_expr)
|
||||
})
|
||||
self.typeck_results
|
||||
.as_ref()
|
||||
.and_then(|typeck_results| typeck_results.expr_ty_opt(arg_expr))
|
||||
} else {
|
||||
bug!("try desugaring w/out call expr as scrutinee");
|
||||
};
|
||||
|
@ -878,8 +884,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
// don't suggest wrapping either blocks in `if .. {} else {}`
|
||||
let is_empty_arm = |id| {
|
||||
let hir::Node::Block(blk) = self.tcx.hir().get(id)
|
||||
else {
|
||||
let hir::Node::Block(blk) = self.tcx.hir().get(id) else {
|
||||
return false;
|
||||
};
|
||||
if blk.expr.is_some() || !blk.stmts.is_empty() {
|
||||
|
@ -908,12 +913,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
_ => {
|
||||
if let ObligationCauseCode::BindingObligation(_, span)
|
||||
| ObligationCauseCode::ExprBindingObligation(_, span, ..)
|
||||
= cause.code().peel_derives()
|
||||
| ObligationCauseCode::ExprBindingObligation(_, span, ..) =
|
||||
cause.code().peel_derives()
|
||||
&& let TypeError::RegionsPlaceholderMismatch = terr
|
||||
{
|
||||
err.span_note( * span,
|
||||
"the lifetime requirement is introduced here");
|
||||
err.span_note(*span, "the lifetime requirement is introduced here");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1742,19 +1746,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| {
|
||||
if let ty::Adt(expected, _) = expected.kind() && let Some(primitive) = found.primitive_symbol() {
|
||||
if let ty::Adt(expected, _) = expected.kind()
|
||||
&& let Some(primitive) = found.primitive_symbol()
|
||||
{
|
||||
let path = self.tcx.def_path(expected.did()).data;
|
||||
let name = path.last().unwrap().data.get_opt_name();
|
||||
if name == Some(primitive) {
|
||||
return Some(Similar::PrimitiveFound { expected: *expected, found });
|
||||
}
|
||||
} else if let Some(primitive) = expected.primitive_symbol() && let ty::Adt(found, _) = found.kind() {
|
||||
} else if let Some(primitive) = expected.primitive_symbol()
|
||||
&& let ty::Adt(found, _) = found.kind()
|
||||
{
|
||||
let path = self.tcx.def_path(found.did()).data;
|
||||
let name = path.last().unwrap().data.get_opt_name();
|
||||
if name == Some(primitive) {
|
||||
return Some(Similar::PrimitiveExpected { expected, found: *found });
|
||||
}
|
||||
} else if let ty::Adt(expected, _) = expected.kind() && let ty::Adt(found, _) = found.kind() {
|
||||
} else if let ty::Adt(expected, _) = expected.kind()
|
||||
&& let ty::Adt(found, _) = found.kind()
|
||||
{
|
||||
if !expected.did().is_local() && expected.did().krate == found.did().krate {
|
||||
// Most likely types from different versions of the same crate
|
||||
// are in play, in which case this message isn't so helpful.
|
||||
|
@ -1764,8 +1774,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
let f_path = self.tcx.def_path(found.did()).data;
|
||||
let e_path = self.tcx.def_path(expected.did()).data;
|
||||
|
||||
if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last()) && e_last == f_last {
|
||||
return Some(Similar::Adts{expected: *expected, found: *found});
|
||||
if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last())
|
||||
&& e_last == f_last
|
||||
{
|
||||
return Some(Similar::Adts { expected: *expected, found: *found });
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -1796,7 +1808,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
};
|
||||
|
||||
let diagnose_adts =
|
||||
|expected_adt : ty::AdtDef<'tcx>,
|
||||
|expected_adt: ty::AdtDef<'tcx>,
|
||||
found_adt: ty::AdtDef<'tcx>,
|
||||
diagnostic: &mut Diagnostic| {
|
||||
let found_name = values.found.sort_string(self.tcx);
|
||||
|
@ -1816,8 +1828,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
.tcx
|
||||
.parent_module_from_def_id(defid.expect_local())
|
||||
.to_def_id();
|
||||
let module_name = self.tcx.def_path(module).to_string_no_crate_verbose();
|
||||
format!("{name} is defined in module `crate{module_name}` of the current crate")
|
||||
let module_name =
|
||||
self.tcx.def_path(module).to_string_no_crate_verbose();
|
||||
format!(
|
||||
"{name} is defined in module `crate{module_name}` of the current crate"
|
||||
)
|
||||
} else if defid.is_local() {
|
||||
format!("{name} is defined in the current crate")
|
||||
} else {
|
||||
|
@ -1829,13 +1844,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
};
|
||||
|
||||
match s {
|
||||
Similar::Adts{expected, found} => {
|
||||
diagnose_adts(expected, found, diag)
|
||||
}
|
||||
Similar::PrimitiveFound{expected, found: prim} => {
|
||||
Similar::Adts { expected, found } => diagnose_adts(expected, found, diag),
|
||||
Similar::PrimitiveFound { expected, found: prim } => {
|
||||
diagnose_primitive(prim, values.expected, expected.did(), diag)
|
||||
}
|
||||
Similar::PrimitiveExpected{expected: prim, found} => {
|
||||
Similar::PrimitiveExpected { expected: prim, found } => {
|
||||
diagnose_primitive(prim, values.found, found.did(), diag)
|
||||
}
|
||||
}
|
||||
|
@ -1877,7 +1890,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
s
|
||||
};
|
||||
if !(values.expected.is_simple_text(self.tcx) && values.found.is_simple_text(self.tcx))
|
||||
if !(values.expected.is_simple_text(self.tcx)
|
||||
&& values.found.is_simple_text(self.tcx))
|
||||
|| (exp_found.is_some_and(|ef| {
|
||||
// This happens when the type error is a subset of the expectation,
|
||||
// like when you have two references but one is `usize` and the other
|
||||
|
@ -1967,13 +1981,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
&& let exp_found = TypeError::Sorts(exp_found)
|
||||
&& exp_found != terr
|
||||
{
|
||||
self.note_and_explain_type_err(
|
||||
diag,
|
||||
exp_found,
|
||||
cause,
|
||||
span,
|
||||
cause.body_id.to_def_id(),
|
||||
);
|
||||
self.note_and_explain_type_err(diag, exp_found, cause, span, cause.body_id.to_def_id());
|
||||
}
|
||||
|
||||
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
|
||||
|
@ -1983,7 +1991,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
{
|
||||
let span = self.tcx.def_span(def_id);
|
||||
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
|
||||
self.suggest_for_all_lifetime_closure(span, self.tcx.hir().get_by_def_id(def_id), &exp_found, diag);
|
||||
self.suggest_for_all_lifetime_closure(
|
||||
span,
|
||||
self.tcx.hir().get_by_def_id(def_id),
|
||||
&exp_found,
|
||||
diag,
|
||||
);
|
||||
}
|
||||
|
||||
// It reads better to have the error origin as the final
|
||||
|
@ -2009,7 +2022,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
// parentheses around it, perhaps the user meant to write `(expr,)` to
|
||||
// build a tuple (issue #86100)
|
||||
(ty::Tuple(fields), _) => {
|
||||
suggestions.extend(self.suggest_wrap_to_build_a_tuple( span, found, fields))
|
||||
suggestions.extend(self.suggest_wrap_to_build_a_tuple(span, found, fields))
|
||||
}
|
||||
// If a byte was expected and the found expression is a char literal
|
||||
// containing a single ASCII character, perhaps the user meant to write `b'c'` to
|
||||
|
@ -2059,8 +2072,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
// For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
|
||||
// we try to suggest to add the missing `let` for `if let Some(..) = expr`
|
||||
(ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
|
||||
suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
|
||||
(ty::Bool, ty::Tuple(list)) => {
|
||||
if list.len() == 0 {
|
||||
suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
|
||||
}
|
||||
}
|
||||
(ty::Array(_, _), ty::Array(_, _)) => {
|
||||
suggestions.extend(self.suggest_specify_actual_length(terr, trace, span))
|
||||
|
@ -2070,8 +2085,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
let code = trace.cause.code();
|
||||
if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. })
|
||||
| BlockTailExpression(.., source)
|
||||
) = code
|
||||
| BlockTailExpression(.., source)) = code
|
||||
&& let hir::MatchSource::TryDesugar(_) = source
|
||||
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
|
||||
{
|
||||
|
@ -2108,17 +2122,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
// Find a local statement where the initializer has
|
||||
// the same span as the error and the type is specified.
|
||||
if let hir::Stmt {
|
||||
kind: hir::StmtKind::Local(hir::Local {
|
||||
init: Some(hir::Expr {
|
||||
span: init_span,
|
||||
kind:
|
||||
hir::StmtKind::Local(hir::Local {
|
||||
init: Some(hir::Expr { span: init_span, .. }),
|
||||
ty: Some(array_ty),
|
||||
..
|
||||
}),
|
||||
ty: Some(array_ty),
|
||||
..
|
||||
}),
|
||||
..
|
||||
} = s
|
||||
&& init_span == &self.span {
|
||||
&& init_span == &self.span
|
||||
{
|
||||
self.result = Some(*array_ty);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -163,13 +163,13 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
|
|||
let ty_vars = infcx_inner.type_variables();
|
||||
let var_origin = ty_vars.var_origin(ty_vid);
|
||||
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind
|
||||
&& name != kw::SelfUpper && !var_origin.span.from_expansion()
|
||||
&& name != kw::SelfUpper
|
||||
&& !var_origin.span.from_expansion()
|
||||
{
|
||||
let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id));
|
||||
let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap();
|
||||
let generic_param_def = generics.param_at(idx as usize, infcx.tcx);
|
||||
if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind
|
||||
{
|
||||
if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind {
|
||||
None
|
||||
} else {
|
||||
Some(name)
|
||||
|
@ -792,8 +792,9 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
|||
let cost = self.source_cost(&new_source) + self.attempt;
|
||||
debug!(?cost);
|
||||
self.attempt += 1;
|
||||
if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source
|
||||
&& let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind
|
||||
if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, .. }, .. }) =
|
||||
self.infer_source
|
||||
&& let InferSourceKind::LetBinding { ref ty, ref mut def_id, .. } = new_source.kind
|
||||
&& ty.is_ty_or_numeric_infer()
|
||||
{
|
||||
// Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
|
||||
|
@ -1242,7 +1243,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
|
|||
successor,
|
||||
args,
|
||||
def_id,
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,7 +214,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
|
||||
_ => cause.code(),
|
||||
}
|
||||
&& let (&ObligationCauseCode::ItemObligation(item_def_id) | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), None) = (code, override_error_code)
|
||||
&& let (
|
||||
&ObligationCauseCode::ItemObligation(item_def_id)
|
||||
| &ObligationCauseCode::ExprItemObligation(item_def_id, ..),
|
||||
None,
|
||||
) = (code, override_error_code)
|
||||
{
|
||||
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
|
||||
// lifetime as above, but called using a fully-qualified path to the method:
|
||||
|
@ -322,13 +326,27 @@ pub fn suggest_new_region_bound(
|
|||
let existing_lt_name = if let Some(id) = scope_def_id
|
||||
&& let Some(generics) = tcx.hir().get_generics(id)
|
||||
&& let named_lifetimes = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }))
|
||||
.map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}})
|
||||
.filter(|n| ! matches!(n, None))
|
||||
.collect::<Vec<_>>()
|
||||
&& named_lifetimes.len() > 0 {
|
||||
.params
|
||||
.iter()
|
||||
.filter(|p| {
|
||||
matches!(
|
||||
p.kind,
|
||||
GenericParamKind::Lifetime {
|
||||
kind: hir::LifetimeParamKind::Explicit
|
||||
}
|
||||
)
|
||||
})
|
||||
.map(|p| {
|
||||
if let hir::ParamName::Plain(name) = p.name {
|
||||
Some(name.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|n| !matches!(n, None))
|
||||
.collect::<Vec<_>>()
|
||||
&& named_lifetimes.len() > 0
|
||||
{
|
||||
named_lifetimes[0].clone()
|
||||
} else {
|
||||
None
|
||||
|
@ -342,30 +360,28 @@ pub fn suggest_new_region_bound(
|
|||
.params
|
||||
.iter()
|
||||
.filter(|p| p.is_elided_lifetime())
|
||||
.map(|p|
|
||||
if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_)
|
||||
(p.span.shrink_to_hi(),format!("{name} "))
|
||||
} else { // Underscore (elided with '_)
|
||||
(p.span, name.to_string())
|
||||
}
|
||||
)
|
||||
.map(|p| {
|
||||
if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) {
|
||||
// Ampersand (elided without '_)
|
||||
(p.span.shrink_to_hi(), format!("{name} "))
|
||||
} else {
|
||||
// Underscore (elided with '_)
|
||||
(p.span, name.to_string())
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
&& spans_suggs.len() > 1
|
||||
{
|
||||
let use_lt =
|
||||
if existing_lt_name == None {
|
||||
let use_lt = if existing_lt_name == None {
|
||||
spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
|
||||
format!("you can introduce a named lifetime parameter `{name}`")
|
||||
} else {
|
||||
// make use the existing named lifetime
|
||||
format!("you can use the named lifetime parameter `{name}`")
|
||||
};
|
||||
spans_suggs
|
||||
.push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
|
||||
spans_suggs.push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
|
||||
err.multipart_suggestion_verbose(
|
||||
format!(
|
||||
"{declare} `{ty}` {captures}, {use_lt}",
|
||||
),
|
||||
format!("{declare} `{ty}` {captures}, {use_lt}",),
|
||||
spans_suggs,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
@ -443,8 +459,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
let trait_did = trait_id.to_def_id();
|
||||
tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
|
||||
if let Node::Item(Item {
|
||||
kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
|
||||
..
|
||||
kind: ItemKind::Impl(hir::Impl { self_ty, .. }), ..
|
||||
}) = tcx.hir().find_by_def_id(impl_did)?
|
||||
&& trait_objects.iter().all(|did| {
|
||||
// FIXME: we should check `self_ty` against the receiver
|
||||
|
|
|
@ -72,32 +72,30 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
#traits-as-parameters",
|
||||
);
|
||||
}
|
||||
(ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => {
|
||||
(
|
||||
ty::Alias(ty::Projection | ty::Inherent, _),
|
||||
ty::Alias(ty::Projection | ty::Inherent, _),
|
||||
) => {
|
||||
diag.note("an associated type was expected, but a different one was found");
|
||||
}
|
||||
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
|
||||
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
|
||||
(ty::Param(p), ty::Alias(ty::Projection, proj))
|
||||
| (ty::Alias(ty::Projection, proj), ty::Param(p))
|
||||
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
|
||||
{
|
||||
let p_def_id = tcx
|
||||
.generics_of(body_owner_def_id)
|
||||
.type_param(p, tcx)
|
||||
.def_id;
|
||||
let p_def_id = tcx.generics_of(body_owner_def_id).type_param(p, tcx).def_id;
|
||||
let p_span = tcx.def_span(p_def_id);
|
||||
if !sp.contains(p_span) {
|
||||
diag.span_label(p_span, "this type parameter");
|
||||
}
|
||||
let hir = tcx.hir();
|
||||
let mut note = true;
|
||||
let parent = p_def_id
|
||||
.as_local()
|
||||
.and_then(|id| {
|
||||
let local_id = hir.local_def_id_to_hir_id(id);
|
||||
let generics = tcx.hir().find_parent(local_id)?.generics()?;
|
||||
Some((id, generics))
|
||||
});
|
||||
if let Some((local_id, generics)) = parent
|
||||
{
|
||||
let parent = p_def_id.as_local().and_then(|id| {
|
||||
let local_id = hir.local_def_id_to_hir_id(id);
|
||||
let generics = tcx.hir().find_parent(local_id)?.generics()?;
|
||||
Some((id, generics))
|
||||
});
|
||||
if let Some((local_id, generics)) = parent {
|
||||
// Synthesize the associated type restriction `Add<Output = Expected>`.
|
||||
// FIXME: extract this logic for use in other diagnostics.
|
||||
let (trait_ref, assoc_args) = proj.trait_ref_and_own_args(tcx);
|
||||
|
@ -112,15 +110,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
let mut matching_span = None;
|
||||
let mut matched_end_of_args = false;
|
||||
for bound in generics.bounds_for_param(local_id) {
|
||||
let potential_spans = bound
|
||||
.bounds
|
||||
.iter()
|
||||
.find_map(|bound| {
|
||||
let bound_trait_path = bound.trait_ref()?.path;
|
||||
let def_id = bound_trait_path.res.opt_def_id()?;
|
||||
let generic_args = bound_trait_path.segments.iter().last().map(|path| path.args());
|
||||
(def_id == trait_ref.def_id).then_some((bound_trait_path.span, generic_args))
|
||||
});
|
||||
let potential_spans = bound.bounds.iter().find_map(|bound| {
|
||||
let bound_trait_path = bound.trait_ref()?.path;
|
||||
let def_id = bound_trait_path.res.opt_def_id()?;
|
||||
let generic_args = bound_trait_path
|
||||
.segments
|
||||
.iter()
|
||||
.last()
|
||||
.map(|path| path.args());
|
||||
(def_id == trait_ref.def_id)
|
||||
.then_some((bound_trait_path.span, generic_args))
|
||||
});
|
||||
|
||||
if let Some((end_of_trait, end_of_args)) = potential_spans {
|
||||
let args_span = end_of_args.and_then(|args| args.span());
|
||||
|
@ -223,7 +223,9 @@ impl<T> Trait<T> for X {
|
|||
diag.span_label(p_span, "this type parameter");
|
||||
}
|
||||
}
|
||||
(ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||
(ty::Alias(ty::Projection | ty::Inherent, proj_ty), _)
|
||||
if !tcx.is_impl_trait_in_trait(proj_ty.def_id) =>
|
||||
{
|
||||
self.expected_projection(
|
||||
diag,
|
||||
proj_ty,
|
||||
|
@ -232,11 +234,15 @@ impl<T> Trait<T> for X {
|
|||
cause.code(),
|
||||
);
|
||||
}
|
||||
(_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
|
||||
let msg = || format!(
|
||||
"consider constraining the associated type `{}` to `{}`",
|
||||
values.found, values.expected,
|
||||
);
|
||||
(_, ty::Alias(ty::Projection | ty::Inherent, proj_ty))
|
||||
if !tcx.is_impl_trait_in_trait(proj_ty.def_id) =>
|
||||
{
|
||||
let msg = || {
|
||||
format!(
|
||||
"consider constraining the associated type `{}` to `{}`",
|
||||
values.found, values.expected,
|
||||
)
|
||||
};
|
||||
if !(self.suggest_constraining_opaque_associated_type(
|
||||
diag,
|
||||
msg,
|
||||
|
@ -256,19 +262,40 @@ impl<T> Trait<T> for X {
|
|||
);
|
||||
}
|
||||
}
|
||||
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::Fn | DefKind::Static(_) | DefKind::Const | DefKind::AssocFn | DefKind::AssocConst) => {
|
||||
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias))
|
||||
if alias.def_id.is_local()
|
||||
&& matches!(
|
||||
tcx.def_kind(body_owner_def_id),
|
||||
DefKind::Fn
|
||||
| DefKind::Static(_)
|
||||
| DefKind::Const
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
) =>
|
||||
{
|
||||
if tcx.is_type_alias_impl_trait(alias.def_id) {
|
||||
if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) {
|
||||
let sp = tcx.def_ident_span(body_owner_def_id).unwrap_or_else(|| tcx.def_span(body_owner_def_id));
|
||||
diag.span_note(sp, "\
|
||||
if !tcx
|
||||
.opaque_types_defined_by(body_owner_def_id.expect_local())
|
||||
.contains(&alias.def_id.expect_local())
|
||||
{
|
||||
let sp = tcx
|
||||
.def_ident_span(body_owner_def_id)
|
||||
.unwrap_or_else(|| tcx.def_span(body_owner_def_id));
|
||||
diag.span_note(
|
||||
sp,
|
||||
"\
|
||||
this item must have the opaque type in its signature \
|
||||
in order to be able to register hidden types");
|
||||
in order to be able to register hidden types",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
(ty::FnPtr(sig), ty::FnDef(def_id, _)) | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
|
||||
(ty::FnPtr(sig), ty::FnDef(def_id, _))
|
||||
| (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
|
||||
if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() {
|
||||
diag.note("unsafe functions cannot be coerced into safe function pointers");
|
||||
diag.note(
|
||||
"unsafe functions cannot be coerced into safe function pointers",
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -616,7 +643,8 @@ fn foo(&self) -> Self::T { String::new() }
|
|||
for item in &items[..] {
|
||||
if let hir::AssocItemKind::Type = item.kind {
|
||||
let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
|
||||
if let hir::Defaultness::Default { has_value: true } = tcx.defaultness(item.id.owner_id)
|
||||
if let hir::Defaultness::Default { has_value: true } =
|
||||
tcx.defaultness(item.id.owner_id)
|
||||
&& self.infcx.can_eq(param_env, assoc_ty, found)
|
||||
{
|
||||
diag.span_label(
|
||||
|
|
|
@ -491,12 +491,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
|
||||
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
|
||||
if let hir::StmtKind::Local(hir::Local {
|
||||
span, pat: hir::Pat{..}, ty: None, init: Some(_), ..
|
||||
}) = &ex.kind
|
||||
&& self.found_if
|
||||
&& span.eq(&self.err_span) {
|
||||
self.result = true;
|
||||
}
|
||||
span,
|
||||
pat: hir::Pat { .. },
|
||||
ty: None,
|
||||
init: Some(_),
|
||||
..
|
||||
}) = &ex.kind
|
||||
&& self.found_if
|
||||
&& span.eq(&self.err_span)
|
||||
{
|
||||
self.result = true;
|
||||
}
|
||||
walk_stmt(self, ex);
|
||||
}
|
||||
|
||||
|
@ -546,45 +551,59 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
let expected = expected.unpack();
|
||||
let found = found.unpack();
|
||||
// 3. Extract the tuple type from Fn trait and suggest the change.
|
||||
if let GenericArgKind::Type(expected) = expected &&
|
||||
let GenericArgKind::Type(found) = found &&
|
||||
let ty::Tuple(expected) = expected.kind() &&
|
||||
let ty::Tuple(found)= found.kind() &&
|
||||
expected.len() == found.len() {
|
||||
if let GenericArgKind::Type(expected) = expected
|
||||
&& let GenericArgKind::Type(found) = found
|
||||
&& let ty::Tuple(expected) = expected.kind()
|
||||
&& let ty::Tuple(found) = found.kind()
|
||||
&& expected.len() == found.len()
|
||||
{
|
||||
let mut suggestion = "|".to_string();
|
||||
let mut is_first = true;
|
||||
let mut has_suggestion = false;
|
||||
|
||||
for (((expected, found), param_hir), arg_hir) in expected.iter()
|
||||
.zip(found.iter())
|
||||
.zip(params.iter())
|
||||
.zip(fn_decl.inputs.iter()) {
|
||||
for (((expected, found), param_hir), arg_hir) in
|
||||
expected.iter().zip(found.iter()).zip(params.iter()).zip(fn_decl.inputs.iter())
|
||||
{
|
||||
if is_first {
|
||||
is_first = false;
|
||||
} else {
|
||||
suggestion += ", ";
|
||||
}
|
||||
|
||||
if let ty::Ref(expected_region, _, _) = expected.kind() &&
|
||||
let ty::Ref(found_region, _, _) = found.kind() &&
|
||||
expected_region.is_late_bound() &&
|
||||
!found_region.is_late_bound() &&
|
||||
let hir::TyKind::Infer = arg_hir.kind {
|
||||
if let ty::Ref(expected_region, _, _) = expected.kind()
|
||||
&& let ty::Ref(found_region, _, _) = found.kind()
|
||||
&& expected_region.is_late_bound()
|
||||
&& !found_region.is_late_bound()
|
||||
&& let hir::TyKind::Infer = arg_hir.kind
|
||||
{
|
||||
// If the expected region is late bound, the found region is not, and users are asking compiler
|
||||
// to infer the type, we can suggest adding `: &_`.
|
||||
if param_hir.pat.span == param_hir.ty_span {
|
||||
// for `|x|`, `|_|`, `|x: impl Foo|`
|
||||
let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
|
||||
let Ok(pat) =
|
||||
self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
suggestion += &format!("{pat}: &_");
|
||||
} else {
|
||||
// for `|x: ty|`, `|_: ty|`
|
||||
let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
|
||||
let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; };
|
||||
let Ok(pat) =
|
||||
self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
suggestion += &format!("{pat}: &{ty}");
|
||||
}
|
||||
has_suggestion = true;
|
||||
} else {
|
||||
let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { return; };
|
||||
let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else {
|
||||
return;
|
||||
};
|
||||
// Otherwise, keep it as-is.
|
||||
suggestion += &arg;
|
||||
}
|
||||
|
|
|
@ -220,7 +220,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
if let ty::ReVar(vid) = *r && self.region_vars.0.contains(&vid) {
|
||||
if let ty::ReVar(vid) = *r
|
||||
&& self.region_vars.0.contains(&vid)
|
||||
{
|
||||
let idx = vid.index() - self.region_vars.0.start.index();
|
||||
let origin = self.region_vars.1[idx];
|
||||
return self.infcx.next_region_var(origin);
|
||||
|
|
|
@ -346,7 +346,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
// tighter bound than `'static`.
|
||||
//
|
||||
// (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
|
||||
if let ty::RePlaceholder(p) = *lub && b_universe.cannot_name(p.universe) {
|
||||
if let ty::RePlaceholder(p) = *lub
|
||||
&& b_universe.cannot_name(p.universe)
|
||||
{
|
||||
lub = self.tcx().lifetimes.re_static;
|
||||
}
|
||||
|
||||
|
|
|
@ -177,7 +177,9 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
|
|||
value: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
debug!("self.pattern_depth = {:?}", self.pattern_depth);
|
||||
if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind() && depth == self.pattern_depth {
|
||||
if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind()
|
||||
&& depth == self.pattern_depth
|
||||
{
|
||||
self.bind(br, value)
|
||||
} else if pattern == value {
|
||||
Ok(pattern)
|
||||
|
|
|
@ -108,20 +108,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
|
||||
|
||||
// Search the env for where clauses like `P: 'a`.
|
||||
let env_bounds = self
|
||||
.approx_declared_bounds_from_env(alias_ty)
|
||||
.into_iter()
|
||||
.map(|binder| {
|
||||
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == alias_ty_as_ty {
|
||||
// Micro-optimize if this is an exact match (this
|
||||
// occurs often when there are no region variables
|
||||
// involved).
|
||||
VerifyBound::OutlivedBy(r)
|
||||
} else {
|
||||
let verify_if_eq_b = binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
|
||||
VerifyBound::IfEq(verify_if_eq_b)
|
||||
}
|
||||
});
|
||||
let env_bounds = self.approx_declared_bounds_from_env(alias_ty).into_iter().map(|binder| {
|
||||
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars()
|
||||
&& ty == alias_ty_as_ty
|
||||
{
|
||||
// Micro-optimize if this is an exact match (this
|
||||
// occurs often when there are no region variables
|
||||
// involved).
|
||||
VerifyBound::OutlivedBy(r)
|
||||
} else {
|
||||
let verify_if_eq_b =
|
||||
binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
|
||||
VerifyBound::IfEq(verify_if_eq_b)
|
||||
}
|
||||
});
|
||||
|
||||
// Extend with bounds that we can find from the definition.
|
||||
let definition_bounds =
|
||||
|
|
|
@ -457,7 +457,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
|||
debug!("RegionConstraintCollector: add_verify({:?})", verify);
|
||||
|
||||
// skip no-op cases known to be satisfied
|
||||
if let VerifyBound::AllBounds(ref bs) = verify.bound && bs.is_empty() {
|
||||
if let VerifyBound::AllBounds(ref bs) = verify.bound
|
||||
&& bs.is_empty()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,9 @@ pub fn report_object_safety_error<'tcx>(
|
|||
let mut multi_span = vec![];
|
||||
let mut messages = vec![];
|
||||
for violation in violations {
|
||||
if let ObjectSafetyViolation::SizedSelf(sp) = &violation && !sp.is_empty() {
|
||||
if let ObjectSafetyViolation::SizedSelf(sp) = &violation
|
||||
&& !sp.is_empty()
|
||||
{
|
||||
// Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations
|
||||
// with a `Span`.
|
||||
reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into()));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue