Rollup merge of #77093 - lcnr:const-generics-infer-warning, r=varkor

merge `need_type_info_err(_const)`

I hoped that this would automatically solve #76737 but it doesn't quite seem like it

fixes #77092

r? @varkor
This commit is contained in:
Ralf Jung 2020-09-26 12:58:17 +02:00 committed by GitHub
commit ac8169dc10
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 253 additions and 154 deletions

View file

@ -176,7 +176,10 @@ fn closure_return_type_suggestion(
suggestion, suggestion,
Applicability::HasPlaceholders, Applicability::HasPlaceholders,
); );
err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); err.span_label(
span,
InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr),
);
} }
/// Given a closure signature, return a `String` containing a list of all its argument types. /// Given a closure signature, return a `String` containing a list of all its argument types.
@ -217,65 +220,151 @@ impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded {
} }
} }
/// Information about a constant or a type containing inference variables.
pub struct InferenceDiagnosticsData {
pub name: String,
pub span: Option<Span>,
pub description: Cow<'static, str>,
pub parent_name: Option<String>,
pub parent_description: Option<&'static str>,
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> { impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn extract_type_name( /// Extracts data used by diagnostic for either types or constants
/// which were stuck during inference.
pub fn extract_inference_diagnostics_data(
&self, &self,
ty: Ty<'tcx>, arg: GenericArg<'tcx>,
highlight: Option<ty::print::RegionHighlightMode>, highlight: Option<ty::print::RegionHighlightMode>,
) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) { ) -> InferenceDiagnosticsData {
if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { match arg.unpack() {
let mut inner = self.inner.borrow_mut(); GenericArgKind::Type(ty) => {
let ty_vars = &inner.type_variables(); if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
let var_origin = ty_vars.var_origin(ty_vid); let mut inner = self.inner.borrow_mut();
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind { let ty_vars = &inner.type_variables();
let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); let var_origin = ty_vars.var_origin(ty_vid);
let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id { if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) =
let parent_name = self var_origin.kind
.tcx {
.def_key(parent_def_id) let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
.disambiguated_data let (parent_name, parent_description) =
.data if let Some(parent_def_id) = parent_def_id {
.get_opt_name() let parent_name = self
.map(|parent_symbol| parent_symbol.to_string()); .tcx
.def_key(parent_def_id)
.disambiguated_data
.data
.get_opt_name()
.map(|parent_symbol| parent_symbol.to_string());
(parent_name, Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id))) (
} else { parent_name,
(None, None) Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
}; )
} else {
(None, None)
};
if name != kw::SelfUpper { if name != kw::SelfUpper {
return ( return InferenceDiagnosticsData {
name.to_string(), name: name.to_string(),
Some(var_origin.span), span: Some(var_origin.span),
"type parameter".into(), description: "type parameter".into(),
parent_name, parent_name,
parent_desc, parent_description,
); };
}
}
}
let mut s = String::new();
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
if let Some(highlight) = highlight {
printer.region_highlight_mode = highlight;
}
let _ = ty.print(printer);
InferenceDiagnosticsData {
name: s,
span: None,
description: ty.prefix_string(),
parent_name: None,
parent_description: None,
} }
} }
} GenericArgKind::Const(ct) => {
if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
let origin =
self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
origin.kind
{
let parent_def_id = self.tcx.parent(def_id);
let (parent_name, parent_description) =
if let Some(parent_def_id) = parent_def_id {
let parent_name = self
.tcx
.def_key(parent_def_id)
.disambiguated_data
.data
.get_opt_name()
.map(|parent_symbol| parent_symbol.to_string());
let mut s = String::new(); (
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); parent_name,
if let Some(highlight) = highlight { Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
printer.region_highlight_mode = highlight; )
} else {
(None, None)
};
return InferenceDiagnosticsData {
name: name.to_string(),
span: Some(origin.span),
description: "const parameter".into(),
parent_name,
parent_description,
};
}
debug_assert!(!origin.span.is_dummy());
let mut s = String::new();
let mut printer =
ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
if let Some(highlight) = highlight {
printer.region_highlight_mode = highlight;
}
let _ = ct.print(printer);
InferenceDiagnosticsData {
name: s,
span: Some(origin.span),
description: "the constant".into(),
parent_name: None,
parent_description: None,
}
} else {
bug!("unexpect const: {:?}", ct);
}
}
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
} }
let _ = ty.print(printer);
(s, None, ty.prefix_string(), None, None)
} }
// FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well. pub fn emit_inference_failure_err(
pub fn need_type_info_err(
&self, &self,
body_id: Option<hir::BodyId>, body_id: Option<hir::BodyId>,
span: Span, span: Span,
ty: Ty<'tcx>, arg: GenericArg<'tcx>,
error_code: TypeAnnotationNeeded, error_code: TypeAnnotationNeeded,
) -> DiagnosticBuilder<'tcx> { ) -> DiagnosticBuilder<'tcx> {
let ty = self.resolve_vars_if_possible(&ty); let arg = self.resolve_vars_if_possible(&arg);
let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); let arg_data = self.extract_inference_diagnostics_data(arg, None);
let kind_str = match arg.unpack() {
GenericArgKind::Type(_) => "type",
GenericArgKind::Const(_) => "the value",
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
};
let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span); let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
let ty_to_string = |ty: Ty<'tcx>| -> String { let ty_to_string = |ty: Ty<'tcx>| -> String {
let mut s = String::new(); let mut s = String::new();
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
@ -305,7 +394,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} }
let err_span = if let Some(pattern) = local_visitor.found_arg_pattern { let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
pattern.span pattern.span
} else if let Some(span) = name_sp { } else if let Some(span) = arg_data.span {
// `span` here lets us point at `sum` instead of the entire right hand side expr: // `span` here lets us point at `sum` instead of the entire right hand side expr:
// error[E0282]: type annotations needed // error[E0282]: type annotations needed
// --> file2.rs:3:15 // --> file2.rs:3:15
@ -352,7 +441,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => String::new(), _ => String::new(),
}; };
// When `name` corresponds to a type argument, show the path of the full type we're // When `arg_data.name` corresponds to a type argument, show the path of the full type we're
// trying to infer. In the following example, `ty_msg` contains // trying to infer. In the following example, `ty_msg` contains
// " in `std::result::Result<i32, E>`": // " in `std::result::Result<i32, E>`":
// ``` // ```
@ -391,11 +480,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
&mut err, &mut err,
&decl.output, &decl.output,
self.tcx.hir().body(body_id), self.tcx.hir().body(body_id),
&descr, &arg_data.description,
&name, &arg_data.name,
&ret, &ret,
parent_name, arg_data.parent_name,
parent_descr, arg_data.parent_description,
); );
// We don't want to give the other suggestions when the problem is the // We don't want to give the other suggestions when the problem is the
// closure return type. // closure return type.
@ -409,15 +498,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// nudge them in the right direction. // nudge them in the right direction.
format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret) format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
} }
Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => { Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
let ty = ty_to_string(ty); let ty = ty_to_string(ty);
format!("the explicit type `{}`, with the type parameters specified", ty) format!("the explicit type `{}`, with the type parameters specified", ty)
} }
Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => { Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
let ty = ty_to_string(ty); let ty = ty_to_string(ty);
format!( format!(
"the explicit type `{}`, where the type parameter `{}` is specified", "the explicit type `{}`, where the type parameter `{}` is specified",
ty, name, ty, arg_data.name,
) )
} }
_ => "a type".to_string(), _ => "a type".to_string(),
@ -534,7 +623,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// | ^^^ cannot infer type for `S` // | ^^^ cannot infer type for `S`
// | // |
// = note: type must be known at this point // = note: type must be known at this point
let span = name_sp.unwrap_or(err_span); let span = arg_data.span.unwrap_or(err_span);
if !err if !err
.span .span
.span_labels() .span_labels()
@ -545,55 +634,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// Avoid multiple labels pointing at `span`. // Avoid multiple labels pointing at `span`.
err.span_label( err.span_label(
span, span,
InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr), InferCtxt::cannot_infer_msg(
kind_str,
&arg_data.name,
&arg_data.description,
arg_data.parent_name,
arg_data.parent_description,
),
); );
} }
err err
} }
// FIXME(const_generics): We should either try and merge this with `need_type_info_err`
// or improve the errors created here.
//
// Unlike for type inference variables, we don't yet store the origin of const inference variables.
// This is needed for to get a more relevant error span.
pub fn need_type_info_err_const(
&self,
body_id: Option<hir::BodyId>,
span: Span,
ct: &'tcx ty::Const<'tcx>,
error_code: TypeAnnotationNeeded,
) -> DiagnosticBuilder<'tcx> {
let mut local_visitor = FindHirNodeVisitor::new(&self, ct.into(), span);
if let Some(body_id) = body_id {
let expr = self.tcx.hir().expect_expr(body_id.hir_id);
local_visitor.visit_expr(expr);
}
let mut param_name = None;
let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
if let ConstVariableOriginKind::ConstParameterDefinition(param) = origin.kind {
param_name = Some(param);
}
origin.span
} else {
local_visitor.target_span
};
let error_code = error_code.into();
let mut err =
self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
if let Some(param_name) = param_name {
err.note(&format!("cannot infer the value of the const parameter `{}`", param_name));
} else {
err.note("unable to infer the value of a const parameter");
}
err
}
/// If the `FnSig` for the method call can be found and type arguments are identified as /// If the `FnSig` for the method call can be found and type arguments are identified as
/// needed, suggest annotating the call, otherwise point out the resulting type of the call. /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
fn annotate_method_call( fn annotate_method_call(
@ -647,7 +700,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> DiagnosticBuilder<'tcx> { ) -> DiagnosticBuilder<'tcx> {
let ty = self.resolve_vars_if_possible(&ty); let ty = self.resolve_vars_if_possible(&ty);
let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); let data = self.extract_inference_diagnostics_data(ty.into(), None);
let mut err = struct_span_err!( let mut err = struct_span_err!(
self.tcx.sess, self.tcx.sess,
@ -656,18 +709,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"type inside {} must be known in this context", "type inside {} must be known in this context",
kind, kind,
); );
err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); err.span_label(
span,
InferCtxt::cannot_infer_msg(
"type",
&data.name,
&data.description,
data.parent_name,
data.parent_description,
),
);
err err
} }
fn missing_type_msg( fn cannot_infer_msg(
kind_str: &str,
type_name: &str, type_name: &str,
descr: &str, descr: &str,
parent_name: Option<String>, parent_name: Option<String>,
parent_descr: Option<&str>, parent_descr: Option<&str>,
) -> Cow<'static, str> { ) -> String {
if type_name == "_" { if type_name == "_" {
"cannot infer type".into() format!("cannot infer {}", kind_str)
} else { } else {
let parent_desc = if let Some(parent_name) = parent_name { let parent_desc = if let Some(parent_name) = parent_name {
let parent_type_descr = if let Some(parent_descr) = parent_descr { let parent_type_descr = if let Some(parent_descr) = parent_descr {
@ -681,7 +744,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"".to_string() "".to_string()
}; };
format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into() // FIXME: We really shouldn't be dealing with strings here
// but instead use a sensible enum for cases like this.
let preposition = if "the value" == kind_str { "of" } else { "for" };
// For example: "cannot infer type for type parameter `T`"
format!(
"cannot infer {} {} {} `{}`{}",
kind_str, preposition, descr, type_name, parent_desc
)
.into()
} }
} }
} }

View file

@ -1163,7 +1163,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} }
GenericParamDefKind::Const { .. } => { GenericParamDefKind::Const { .. } => {
let origin = ConstVariableOrigin { let origin = ConstVariableOrigin {
kind: ConstVariableOriginKind::ConstParameterDefinition(param.name), kind: ConstVariableOriginKind::ConstParameterDefinition(
param.name,
param.def_id,
),
span, span,
}; };
let const_var_id = let const_var_id =

View file

@ -4,8 +4,9 @@ use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify::{ use rustc_data_structures::unify::{
self, EqUnifyValue, InPlace, NoError, UnificationTable, UnifyKey, UnifyValue, self, EqUnifyValue, InPlace, NoError, UnificationTable, UnifyKey, UnifyValue,
}; };
use rustc_span::def_id::DefId;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::Span;
use std::cmp; use std::cmp;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -124,8 +125,7 @@ pub struct ConstVariableOrigin {
pub enum ConstVariableOriginKind { pub enum ConstVariableOriginKind {
MiscVariable, MiscVariable,
ConstInference, ConstInference,
// FIXME(const_generics): Consider storing the `DefId` of the param here. ConstParameterDefinition(Symbol, DefId),
ConstParameterDefinition(Symbol),
SubstitutionPlaceholder, SubstitutionPlaceholder,
} }
@ -176,17 +176,17 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>); type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> { fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
let val = match (value1.val, value2.val) { let (val, span) = match (value1.val, value2.val) {
(ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => { (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
bug!("equating two const variables, both of which have known values") bug!("equating two const variables, both of which have known values")
} }
// If one side is known, prefer that one. // If one side is known, prefer that one.
(ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => { (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => {
Ok(value1.val) (value1.val, value1.origin.span)
} }
(ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => { (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => {
Ok(value2.val) (value2.val, value2.origin.span)
} }
// If both sides are *unknown*, it hardly matters, does it? // If both sides are *unknown*, it hardly matters, does it?
@ -200,14 +200,14 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
// universe is the minimum of the two universes, because that is // universe is the minimum of the two universes, because that is
// the one which contains the fewest names in scope. // the one which contains the fewest names in scope.
let universe = cmp::min(universe1, universe2); let universe = cmp::min(universe1, universe2);
Ok(ConstVariableValue::Unknown { universe }) (ConstVariableValue::Unknown { universe }, value1.origin.span)
} }
}?; };
Ok(ConstVarValue { Ok(ConstVarValue {
origin: ConstVariableOrigin { origin: ConstVariableOrigin {
kind: ConstVariableOriginKind::ConstInference, kind: ConstVariableOriginKind::ConstInference,
span: DUMMY_SP, span: span,
}, },
val, val,
}) })

View file

@ -396,7 +396,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
) -> Option<RegionNameHighlight> { ) -> Option<RegionNameHighlight> {
let mut highlight = RegionHighlightMode::default(); let mut highlight = RegionHighlightMode::default();
highlight.highlighting_region_vid(needle_fr, counter); highlight.highlighting_region_vid(needle_fr, counter);
let type_name = self.infcx.extract_type_name(&ty, Some(highlight)).0; let type_name =
self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
debug!( debug!(
"highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
@ -404,7 +405,6 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
); );
if type_name.find(&format!("'{}", counter)).is_some() { if type_name.find(&format!("'{}", counter)).is_some() {
// Only add a label if we can confirm that a region was labelled. // Only add a label if we can confirm that a region was labelled.
Some(RegionNameHighlight::CannotMatchHirTy(span, type_name)) Some(RegionNameHighlight::CannotMatchHirTy(span, type_name))
} else { } else {
None None
@ -646,7 +646,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let mut highlight = RegionHighlightMode::default(); let mut highlight = RegionHighlightMode::default();
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0; let type_name =
self.infcx.extract_inference_diagnostics_data(return_ty.into(), Some(highlight)).name;
let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
@ -698,7 +699,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let mut highlight = RegionHighlightMode::default(); let mut highlight = RegionHighlightMode::default();
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0; let type_name =
self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;
let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);

View file

@ -20,7 +20,6 @@ use rustc_hir::Node;
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
TypeFoldable, WithConstness, TypeFoldable, WithConstness,
@ -1513,10 +1512,21 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
// check upstream for type errors and don't add the obligations to // check upstream for type errors and don't add the obligations to
// begin with in those cases. // begin with in those cases.
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); self.emit_inference_failure_err(
body_id,
span,
self_ty.into(),
ErrorCode::E0282,
)
.emit();
return; return;
} }
let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283); let mut err = self.emit_inference_failure_err(
body_id,
span,
self_ty.into(),
ErrorCode::E0283,
);
err.note(&format!("cannot satisfy `{}`", predicate)); err.note(&format!("cannot satisfy `{}`", predicate));
if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
@ -1580,17 +1590,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
return; return;
} }
match arg.unpack() { self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282)
GenericArgKind::Lifetime(lt) => {
span_bug!(span, "unexpected well formed predicate: {:?}", lt)
}
GenericArgKind::Type(ty) => {
self.need_type_info_err(body_id, span, ty, ErrorCode::E0282)
}
GenericArgKind::Const(ct) => {
self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282)
}
}
} }
ty::PredicateAtom::Subtype(data) => { ty::PredicateAtom::Subtype(data) => {
@ -1601,7 +1601,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
let SubtypePredicate { a_is_expected: _, a, b } = data; let SubtypePredicate { a_is_expected: _, a, b } = data;
// both must be type variables, or the other would've been instantiated // both must be type variables, or the other would've been instantiated
assert!(a.is_ty_var() && b.is_ty_var()); assert!(a.is_ty_var() && b.is_ty_var());
self.need_type_info_err(body_id, span, a, ErrorCode::E0282) self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282)
} }
ty::PredicateAtom::Projection(data) => { ty::PredicateAtom::Projection(data) => {
let trait_ref = ty::Binder::bind(data).to_poly_trait_ref(self.tcx); let trait_ref = ty::Binder::bind(data).to_poly_trait_ref(self.tcx);
@ -1612,7 +1612,12 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
} }
if self_ty.needs_infer() && ty.needs_infer() { if self_ty.needs_infer() && ty.needs_infer() {
// We do this for the `foo.collect()?` case to produce a suggestion. // We do this for the `foo.collect()?` case to produce a suggestion.
let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); let mut err = self.emit_inference_failure_err(
body_id,
span,
self_ty.into(),
ErrorCode::E0284,
);
err.note(&format!("cannot satisfy `{}`", predicate)); err.note(&format!("cannot satisfy `{}`", predicate));
err err
} else { } else {

View file

@ -2991,7 +2991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty ty
} else { } else {
if !self.is_tainted_by_errors() { if !self.is_tainted_by_errors() {
self.need_type_info_err((**self).body_id, sp, ty, E0282) self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282)
.note("type must be known at this point") .note("type must be known at this point")
.emit(); .emit();
} }

View file

@ -653,7 +653,12 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
fn report_type_error(&self, t: Ty<'tcx>) { fn report_type_error(&self, t: Ty<'tcx>) {
if !self.tcx.sess.has_errors() { if !self.tcx.sess.has_errors() {
self.infcx self.infcx
.need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, E0282) .emit_inference_failure_err(
Some(self.body.id()),
self.span.to_span(self.tcx),
t.into(),
E0282,
)
.emit(); .emit();
} }
} }
@ -661,10 +666,10 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) { fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) {
if !self.tcx.sess.has_errors() { if !self.tcx.sess.has_errors() {
self.infcx self.infcx
.need_type_info_err_const( .emit_inference_failure_err(
Some(self.body.id()), Some(self.body.id()),
self.span.to_span(self.tcx), self.span.to_span(self.tcx),
c, c.into(),
E0282, E0282,
) )
.emit(); .emit();

View file

@ -2,9 +2,7 @@ error[E0282]: type annotations needed
--> $DIR/cannot-infer-const-args.rs:12:5 --> $DIR/cannot-infer-const-args.rs:12:5
| |
LL | foo(); LL | foo();
| ^^^ | ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
|
= note: cannot infer the value of the const parameter `X`
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,9 +2,7 @@ error[E0282]: type annotations needed
--> $DIR/cannot-infer-const-args.rs:12:5 --> $DIR/cannot-infer-const-args.rs:12:5
| |
LL | foo(); LL | foo();
| ^^^ | ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
|
= note: cannot infer the value of the const parameter `X`
error: aborting due to previous error error: aborting due to previous error

View file

@ -0,0 +1,16 @@
#![feature(min_const_generics)]
use std::convert::TryInto;
fn take_array_from_mut<T, const N: usize>(data: &mut [T], start: usize) -> &mut [T; N] {
(&mut data[start .. start + N]).try_into().unwrap()
}
fn main() {
let mut arr = [0, 1, 2, 3, 4, 5, 6, 7, 8];
for i in 1 .. 4 {
println!("{:?}", take_array_from_mut(&mut arr, i));
//~^ ERROR type annotations needed
}
}

View file

@ -0,0 +1,9 @@
error[E0282]: type annotations needed
--> $DIR/issue-77092.rs:13:26
|
LL | println!("{:?}", take_array_from_mut(&mut arr, i));
| ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{_: usize}`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.

View file

@ -2,9 +2,7 @@ error[E0282]: type annotations needed
--> $DIR/method-chain.rs:21:33 --> $DIR/method-chain.rs:21:33
| |
LL | Foo.bar().bar().bar().bar().baz(); LL | Foo.bar().bar().bar().bar().baz();
| ^^^ | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
|
= note: cannot infer the value of the const parameter `N`
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,9 +2,7 @@ error[E0282]: type annotations needed
--> $DIR/method-chain.rs:21:33 --> $DIR/method-chain.rs:21:33
| |
LL | Foo.bar().bar().bar().bar().baz(); LL | Foo.bar().bar().bar().bar().baz();
| ^^^ | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
|
= note: cannot infer the value of the const parameter `N`
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,9 +2,7 @@ error[E0282]: type annotations needed
--> $DIR/uninferred-consts.rs:14:9 --> $DIR/uninferred-consts.rs:14:9
| |
LL | Foo.foo(); LL | Foo.foo();
| ^^^ | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo`
|
= note: cannot infer the value of the const parameter `N`
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,9 +2,7 @@ error[E0282]: type annotations needed
--> $DIR/uninferred-consts.rs:14:9 --> $DIR/uninferred-consts.rs:14:9
| |
LL | Foo.foo(); LL | Foo.foo();
| ^^^ | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo`
|
= note: cannot infer the value of the const parameter `N`
error: aborting due to previous error error: aborting due to previous error