mod op;
use crate::astconv::{AstConv, PathSeg};
-use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralise};
use rustc::hir::{self, ExprKind, GenericArg, ItemKind, Node, PatKind, QPath};
use rustc::hir::def::{CtorOf, Res, DefKind};
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::query::Providers;
-use rustc::ty::subst::{UnpackedKind, Subst, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
+use rustc::ty::subst::{
+ GenericArgKind, Subst, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts,
+};
use rustc::ty::util::{Representability, IntTypeExt, Discr};
use rustc::ty::layout::VariantIdx;
use syntax_pos::{self, BytePos, Span, MultiSpan};
use self::TupleArgumentsFlag::*;
/// The type of a local binding, including the revealed type for anon types.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
pub struct LocalTy<'tcx> {
decl_ty: Ty<'tcx>,
revealed_ty: Ty<'tcx>
/// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
/// for examples of where this comes up,.
fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
- match fcx.tcx.struct_tail_without_normalization(ty).sty {
+ match fcx.tcx.struct_tail_without_normalization(ty).kind {
ty::Slice(_) | ty::Str | ty::Dynamic(..) => {
ExpectRvalueLikeUnsized(ty)
}
/// Definitely known to diverge and therefore
/// not reach the next sibling or its parent.
- Always,
+ Always {
+ /// The `Span` points to the expression
+ /// that caused us to diverge
+ /// (e.g. `return`, `break`, etc).
+ span: Span,
+ /// In some cases (e.g. a `match` expression
+ /// where all arms diverge), we may be
+ /// able to provide a more informative
+ /// message to the user.
+ /// If this is `None`, a default messsage
+ /// will be generated, which is suitable
+ /// for most cases.
+ custom_note: Option<&'static str>
+ },
/// Same as `Always` but with a reachability
/// warning already emitted.
}
impl Diverges {
- fn always(self) -> bool {
- self >= Diverges::Always
+ /// Creates a `Diverges::Always` with the provided `span` and the default note message.
+ fn always(span: Span) -> Diverges {
+ Diverges::Always {
+ span,
+ custom_note: None
+ }
+ }
+
+ fn is_always(self) -> bool {
+ // Enum comparison ignores the
+ // contents of fields, so we just
+ // fill them in with garbage here.
+ self >= Diverges::Always {
+ span: DUMMY_SP,
+ custom_note: None
+ }
}
}
) -> Option<(hir::BodyId, Option<&hir::Ty>, Option<&hir::FnHeader>, Option<&hir::FnDecl>)> {
match tcx.hir().get(id) {
Node::Item(item) => {
- match item.node {
+ match item.kind {
hir::ItemKind::Const(ref ty, body) |
hir::ItemKind::Static(ref ty, _, body) =>
Some((body, Some(ty), None, None)),
}
}
Node::TraitItem(item) => {
- match item.node {
+ match item.kind {
hir::TraitItemKind::Const(ref ty, Some(body)) =>
Some((body, Some(ty), None, None)),
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) =>
}
}
Node::ImplItem(item) => {
- match item.node {
+ match item.kind {
hir::ImplItemKind::Const(ref ty, body) =>
Some((body, Some(ty), None, None)),
hir::ImplItemKind::Method(ref sig, body) =>
fcx
} else {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
- let expected_type = body_ty.and_then(|ty| match ty.node {
+ let expected_type = body_ty.and_then(|ty| match ty.kind {
hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)),
_ => None
}).unwrap_or_else(|| tcx.type_of(def_id));
// Add pattern bindings.
fn visit_pat(&mut self, p: &'tcx hir::Pat) {
- if let PatKind::Binding(_, _, ident, _) = p.node {
+ if let PatKind::Binding(_, _, ident, _) = p.kind {
let var_ty = self.assign(p.span, p.hir_id, None);
if !self.fcx.tcx.features().unsized_locals {
// only happens if compilation succeeded
fcx.tcx.sess.has_panic_handler.try_set_same(true);
- if declared_ret_ty.sty != ty::Never {
+ if declared_ret_ty.kind != ty::Never {
fcx.tcx.sess.span_err(
decl.output.span(),
"return type should be `!`",
let inputs = fn_sig.inputs();
let span = fcx.tcx.hir().span(fn_id);
if inputs.len() == 1 {
- let arg_is_panic_info = match inputs[0].sty {
- ty::Ref(region, ty, mutbl) => match ty.sty {
+ let arg_is_panic_info = match inputs[0].kind {
+ ty::Ref(region, ty, mutbl) => match ty.kind {
ty::Adt(ref adt, _) => {
adt.did == panic_info_did &&
mutbl == hir::Mutability::MutImmutable &&
}
if let Node::Item(item) = fcx.tcx.hir().get(fn_id) {
- if let ItemKind::Fn(_, _, ref generics, _) = item.node {
+ if let ItemKind::Fn(_, _, ref generics, _) = item.kind {
if !generics.params.is_empty() {
fcx.tcx.sess.span_err(
span,
if let Some(alloc_error_handler_did) = fcx.tcx.lang_items().oom() {
if alloc_error_handler_did == fcx.tcx.hir().local_def_id(fn_id) {
if let Some(alloc_layout_did) = fcx.tcx.lang_items().alloc_layout() {
- if declared_ret_ty.sty != ty::Never {
+ if declared_ret_ty.kind != ty::Never {
fcx.tcx.sess.span_err(
decl.output.span(),
"return type should be `!`",
let inputs = fn_sig.inputs();
let span = fcx.tcx.hir().span(fn_id);
if inputs.len() == 1 {
- let arg_is_alloc_layout = match inputs[0].sty {
+ let arg_is_alloc_layout = match inputs[0].kind {
ty::Adt(ref adt, _) => {
adt.did == alloc_layout_did
},
}
if let Node::Item(item) = fcx.tcx.hir().get(fn_id) {
- if let ItemKind::Fn(_, _, ref generics, _) = item.node {
+ if let ItemKind::Fn(_, _, ref generics, _) = item.kind {
if !generics.params.is_empty() {
fcx.tcx.sess.span_err(
span,
}
}
- let prohibit_opaque = match item.node {
+ let prohibit_opaque = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::AsyncFn, .. }) |
ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn, .. }) => {
let mut visitor = ProhibitOpaqueVisitor {
debug!("check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}", prohibit_opaque);
if prohibit_opaque {
- let is_async = match item.node {
+ let is_async = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
hir::OpaqueTyOrigin::AsyncFn => true,
_ => false,
"opaque type expands to a recursive type",
);
err.span_label(span, "expands to a recursive type");
- if let ty::Opaque(..) = partially_expanded_type.sty {
+ if let ty::Opaque(..) = partially_expanded_type.kind {
err.note("type resolves to itself");
} else {
err.note(&format!("expanded type is `{}`", partially_expanded_type));
tcx.def_path_str(tcx.hir().local_def_id(it.hir_id))
);
let _indenter = indenter();
- match it.node {
+ match it.kind {
// Consts can play a role in type-checking, so they are included here.
hir::ItemKind::Static(..) => {
let def_id = tcx.hir().local_def_id(it.hir_id);
for item in items.iter() {
let item = tcx.hir().trait_item(item.id);
- if let hir::TraitItemKind::Method(sig, _) = &item.node {
+ if let hir::TraitItemKind::Method(sig, _) = &item.kind {
let abi = sig.header.abi;
fn_maybe_err(tcx, item.ident.span, abi);
}
).emit();
}
- if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node {
+ if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind {
require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span);
}
}
) {
let ancestors = trait_def.ancestors(tcx, impl_id);
- let kind = match impl_item.node {
+ let kind = match impl_item.kind {
hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
hir::ImplItemKind::Method(..) => ty::AssocKind::Method,
hir::ImplItemKind::OpaqueTy(..) => ty::AssocKind::OpaqueTy,
let ty_impl_item = tcx.associated_item(
tcx.hir().local_def_id(impl_item.hir_id));
let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id)
- .find(|ac| Namespace::from(&impl_item.node) == Namespace::from(ac.kind) &&
+ .find(|ac| Namespace::from(&impl_item.kind) == Namespace::from(ac.kind) &&
tcx.hygienic_eq(ty_impl_item.ident, ac.ident, impl_trait_ref.def_id))
.or_else(|| {
// Not compatible, but needed for the error message
// Check that impl definition matches trait definition
if let Some(ty_trait_item) = ty_trait_item {
- match impl_item.node {
+ match impl_item.kind {
hir::ImplItemKind::Const(..) => {
// Find associated const definition.
if ty_trait_item.kind == ty::AssocKind::Const {
pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
let t = tcx.type_of(def_id);
- if let ty::Adt(def, substs) = t.sty {
+ if let ty::Adt(def, substs) = t.kind {
if def.is_struct() {
let fields = &def.non_enum_variant().fields;
if fields.is_empty() {
.emit();
return;
}
- match e.sty {
+ match e.kind {
ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
_ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
_ => {
debug!("check_packed_inner: {:?} is recursive", t);
return false;
}
- if let ty::Adt(def, substs) = t.sty {
+ if let ty::Adt(def, substs) = t.kind {
if def.is_struct() || def.is_union() {
if tcx.adt_def(def.did).repr.align.is_some() {
return true;
stack.push(def_id);
for field in &def.non_enum_variant().fields {
let f = field.ty(tcx, substs);
- if let ty::Adt(def, _) = f.sty {
+ if let ty::Adt(def, _) = f.kind {
if check_packed_inner(tcx, def.did, stack) {
return true;
}
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
if let Some(param) = param {
- if let UnpackedKind::Type(ty) = self.var_for_def(span, param).unpack() {
+ if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
return ty;
}
unreachable!()
span: Span,
) -> &'tcx Const<'tcx> {
if let Some(param) = param {
- if let UnpackedKind::Const(ct) = self.var_for_def(span, param).unpack() {
+ if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
return ct;
}
unreachable!()
/// Produces warning on the given node, if the current point in the
/// function is unreachable, and there hasn't been another warning.
fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) {
- if self.diverges.get() == Diverges::Always &&
+ // FIXME: Combine these two 'if' expressions into one once
+ // let chains are implemented
+ if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() {
// If span arose from a desugaring of `if` or `while`, then it is the condition itself,
// which diverges, that we are about to lint on. This gives suboptimal diagnostics.
// Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
- !span.is_desugaring(DesugaringKind::CondTemporary) {
- self.diverges.set(Diverges::WarnedAlways);
-
- debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
-
- let msg = format!("unreachable {}", kind);
- self.tcx().lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, &msg);
+ if !span.is_desugaring(DesugaringKind::CondTemporary) &&
+ !span.is_desugaring(DesugaringKind::Async)
+ {
+ self.diverges.set(Diverges::WarnedAlways);
+
+ debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
+
+ let msg = format!("unreachable {}", kind);
+ self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, &msg)
+ .span_label(span, &msg)
+ .span_label(
+ orig_span,
+ custom_note.unwrap_or("any code following this expression is unreachable"),
+ )
+ .emit();
+ }
}
}
/// As `instantiate_type_scheme`, but for the bounds found in a
/// generic type scheme.
- fn instantiate_bounds(&self, span: Span, def_id: DefId, substs: SubstsRef<'tcx>)
- -> ty::InstantiatedPredicates<'tcx> {
+ fn instantiate_bounds(
+ &self,
+ span: Span,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
let bounds = self.tcx.predicates_of(def_id);
+ let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
let result = bounds.instantiate(self.tcx, substs);
let result = self.normalize_associated_types_in(span, &result);
- debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}",
+ debug!(
+ "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
bounds,
substs,
- result);
- result
+ result,
+ spans,
+ );
+ (result, spans)
}
/// Replaces the opaque types from the given value with type variables,
traits::ObligationCause::new(span, self.body_id, code));
}
- pub fn require_type_is_sized(&self,
- ty: Ty<'tcx>,
- span: Span,
- code: traits::ObligationCauseCode<'tcx>)
- {
- let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
- self.require_type_meets(ty, span, code, lang_item);
+ pub fn require_type_is_sized(
+ &self,
+ ty: Ty<'tcx>,
+ span: Span,
+ code: traits::ObligationCauseCode<'tcx>,
+ ) {
+ if !ty.references_error() {
+ let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
+ self.require_type_meets(ty, span, code, lang_item);
+ }
}
- pub fn require_type_is_sized_deferred(&self,
- ty: Ty<'tcx>,
- span: Span,
- code: traits::ObligationCauseCode<'tcx>)
- {
- self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
+ pub fn require_type_is_sized_deferred(
+ &self,
+ ty: Ty<'tcx>,
+ span: Span,
+ code: traits::ObligationCauseCode<'tcx>,
+ ) {
+ if !ty.references_error() {
+ self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
+ }
}
- pub fn register_bound(&self,
- ty: Ty<'tcx>,
- def_id: DefId,
- cause: traits::ObligationCause<'tcx>)
- {
- self.fulfillment_cx.borrow_mut()
- .register_bound(self, self.param_env, ty, def_id, cause);
+ pub fn register_bound(
+ &self,
+ ty: Ty<'tcx>,
+ def_id: DefId,
+ cause: traits::ObligationCause<'tcx>,
+ ) {
+ if !ty.references_error() {
+ self.fulfillment_cx.borrow_mut()
+ .register_bound(self, self.param_env, ty, def_id, cause);
+ }
}
pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
/// Registers an obligation for checking later, during regionck, that the type `ty` must
/// outlive the region `r`.
- pub fn register_wf_obligation(&self,
- ty: Ty<'tcx>,
- span: Span,
- code: traits::ObligationCauseCode<'tcx>)
- {
+ pub fn register_wf_obligation(
+ &self,
+ ty: Ty<'tcx>,
+ span: Span,
+ code: traits::ObligationCauseCode<'tcx>,
+ ) {
// WF obligations never themselves fail, so no real need to give a detailed cause:
let cause = traits::ObligationCause::new(span, self.body_id, code);
- self.register_predicate(traits::Obligation::new(cause,
- self.param_env,
- ty::Predicate::WellFormed(ty)));
+ self.register_predicate(
+ traits::Obligation::new(cause, self.param_env, ty::Predicate::WellFormed(ty)),
+ );
}
/// Registers obligations that all types appearing in `substs` are well-formed.
pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr) {
for ty in substs.types() {
- self.register_wf_obligation(ty, expr.span, traits::MiscObligation);
+ if !ty.references_error() {
+ self.register_wf_obligation(ty, expr.span, traits::MiscObligation);
+ }
}
}
// FIXME(arielb1): use this instead of field.ty everywhere
// Only for fields! Returns <none> for methods>
// Indifferent to privacy flags
- pub fn field_ty(&self,
- span: Span,
- field: &'tcx ty::FieldDef,
- substs: SubstsRef<'tcx>)
- -> Ty<'tcx>
- {
+ pub fn field_ty(
+ &self,
+ span: Span,
+ field: &'tcx ty::FieldDef,
+ substs: SubstsRef<'tcx>,
+ ) -> Ty<'tcx> {
self.normalize_associated_types_in(span, &field.ty(self.tcx, substs))
}
let mut self_ty = adjusted_ty;
if unsize {
// We only unsize arrays here.
- if let ty::Array(element_ty, _) = adjusted_ty.sty {
+ if let ty::Array(element_ty, _) = adjusted_ty.kind {
self_ty = self.tcx.mk_slice(element_ty);
} else {
continue;
let method = self.register_infer_ok_obligations(ok);
let mut adjustments = autoderef.adjust_steps(self, needs);
- if let ty::Ref(region, _, r_mutbl) = method.sig.inputs()[0].sty {
+ if let ty::Ref(region, _, r_mutbl) = method.sig.inputs()[0].kind {
let mutbl = match r_mutbl {
hir::MutImmutable => AutoBorrowMutability::Immutable,
hir::MutMutable => AutoBorrowMutability::Mutable {
fn check_method_argument_types(
&self,
sp: Span,
- expr_sp: Span,
+ expr: &'tcx hir::Expr,
method: Result<MethodCallee<'tcx>, ()>,
args_no_rcvr: &'tcx [hir::Expr],
tuple_arguments: TupleArgumentsFlag,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
+
let has_error = match method {
Ok(method) => {
method.substs.references_error() || method.sig.references_error()
TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
};
- self.check_argument_types(sp, expr_sp, &err_inputs[..], &[], args_no_rcvr,
- false, tuple_arguments, None);
+ self.check_argument_types(
+ sp,
+ expr,
+ &err_inputs[..],
+ &[],
+ args_no_rcvr,
+ false,
+ tuple_arguments,
+ None,
+ );
return self.tcx.types.err;
}
method.sig.output(),
&method.sig.inputs()[1..]
);
- self.check_argument_types(sp, expr_sp, &method.sig.inputs()[1..], &expected_arg_tys[..],
- args_no_rcvr, method.sig.c_variadic, tuple_arguments,
- self.tcx.hir().span_if_local(method.def_id));
+ self.check_argument_types(
+ sp,
+ expr,
+ &method.sig.inputs()[1..],
+ &expected_arg_tys[..],
+ args_no_rcvr,
+ method.sig.c_variadic,
+ tuple_arguments,
+ self.tcx.hir().span_if_local(method.def_id),
+ );
method.sig.output()
}
"self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
trait_ref, self_ty, expected_vid
);
- match self_ty.sty {
+ match self_ty.kind {
ty::Infer(ty::TyVar(found_vid)) => {
// FIXME: consider using `sub_root_var` here so we
// can see through subtyping.
fn check_argument_types(
&self,
sp: Span,
- expr_sp: Span,
+ expr: &'tcx hir::Expr,
fn_inputs: &[Ty<'tcx>],
expected_arg_tys: &[Ty<'tcx>],
args: &'tcx [hir::Expr],
def_span: Option<Span>,
) {
let tcx = self.tcx;
-
// Grab the argument types, supplying fresh type variables
// if the wrong number of arguments were supplied
let supplied_arg_count = if tuple_arguments == DontTupleArguments {
// All the input types from the fn signature must outlive the call
// so as to validate implied bounds.
- for &fn_input_ty in fn_inputs {
- self.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation);
+ for (fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) {
+ self.register_wf_obligation(fn_input_ty, arg_expr.span, traits::MiscObligation);
}
let expected_arg_count = fn_inputs.len();
err.span_label(def_s, "defined here");
}
if sugg_unit {
- let sugg_span = tcx.sess.source_map().end_point(expr_sp);
+ let sugg_span = tcx.sess.source_map().end_point(expr.span);
// remove closing `)` from the span
let sugg_span = sugg_span.shrink_to_lo();
err.span_suggestion(
let formal_tys = if tuple_arguments == TupleArguments {
let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
- match tuple_type.sty {
+ match tuple_type.kind {
ty::Tuple(arg_types) if arg_types.len() != args.len() => {
param_count_error(arg_types.len(), args.len(), "E0057", false, false);
expected_arg_tys = vec![];
}
ty::Tuple(arg_types) => {
expected_arg_tys = match expected_arg_tys.get(0) {
- Some(&ty) => match ty.sty {
+ Some(&ty) => match ty.kind {
ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
_ => vec![],
},
// the call. This helps coercions.
if check_closures {
self.select_obligations_where_possible(false, |errors| {
+ self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
self.point_at_arg_instead_of_call_if_possible(
errors,
&final_arg_types[..],
self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
}
- let is_closure = match arg.node {
+ let is_closure = match arg.kind {
ExprKind::Closure(..) => true,
_ => false
};
// There are a few types which get autopromoted when passed via varargs
// in C but we just error out instead and require explicit casts.
let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
- match arg_ty.sty {
+ match arg_ty.kind {
ty::Float(ast::FloatTy::F32) => {
variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
}
vec![self.tcx.types.err; len]
}
+ /// Given a vec of evaluated `FullfillmentError`s and an `fn` call argument expressions, we
+ /// walk the resolved types for each argument to see if any of the `FullfillmentError`s
+ /// reference a type argument. If they do, and there's only *one* argument that does, we point
+ /// at the corresponding argument's expression span instead of the `fn` call path span.
fn point_at_arg_instead_of_call_if_possible(
&self,
errors: &mut Vec<traits::FulfillmentError<'_>>,
// the `?` operator.
for error in errors {
if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
+ // Collect the argument position for all arguments that could have caused this
+ // `FullfillmentError`.
let mut referenced_in = final_arg_types.iter()
.flat_map(|(i, ty)| {
let ty = self.resolve_vars_if_possible(ty);
+ // We walk the argument type because the argument's type could have
+ // been `Option<T>`, but the `FullfillmentError` references `T`.
ty.walk()
.filter(|&ty| ty == predicate.skip_binder().self_ty())
.map(move |_| *i)
}
}
+ /// Given a vec of evaluated `FullfillmentError`s and an `fn` call expression, we walk the
+ /// `PathSegment`s and resolve their type parameters to see if any of the `FullfillmentError`s
+ /// were caused by them. If they were, we point at the corresponding type argument's span
+ /// instead of the `fn` call path span.
+ fn point_at_type_arg_instead_of_call_if_possible(
+ &self,
+ errors: &mut Vec<traits::FulfillmentError<'_>>,
+ call_expr: &'tcx hir::Expr,
+ ) {
+ if let hir::ExprKind::Call(path, _) = &call_expr.kind {
+ if let hir::ExprKind::Path(qpath) = &path.kind {
+ if let hir::QPath::Resolved(_, path) = &qpath {
+ for error in errors {
+ if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
+ // If any of the type arguments in this path segment caused the
+ // `FullfillmentError`, point at its span (#61860).
+ for arg in path.segments.iter()
+ .filter_map(|seg| seg.args.as_ref())
+ .flat_map(|a| a.args.iter())
+ {
+ if let hir::GenericArg::Type(hir_ty) = &arg {
+ if let hir::TyKind::Path(
+ hir::QPath::TypeRelative(..),
+ ) = &hir_ty.kind {
+ // Avoid ICE with associated types. As this is best
+ // effort only, it's ok to ignore the case. It
+ // would trigger in `is_send::<T::AssocType>();`
+ // from `typeck-default-trait-impl-assoc-type.rs`.
+ } else {
+ let ty = AstConv::ast_ty_to_ty(self, hir_ty);
+ let ty = self.resolve_vars_if_possible(&ty);
+ if ty == predicate.skip_binder().self_ty() {
+ error.obligation.cause.span = hir_ty.span;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
// AST fragment checking
fn check_lit(&self,
lit: &hir::Lit,
ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
let opt_ty = expected.to_option(self).and_then(|ty| {
- match ty.sty {
+ match ty.kind {
ty::Int(_) | ty::Uint(_) => Some(ty),
ty::Char => Some(tcx.types.u8),
ty::RawPtr(..) => Some(tcx.types.usize),
ast::LitKind::Float(_, t) => tcx.mk_mach_float(t),
ast::LitKind::FloatUnsuffixed(_) => {
let opt_ty = expected.to_option(self).and_then(|ty| {
- match ty.sty {
+ match ty.kind {
ty::Float(_) => Some(ty),
_ => None
}
return None;
}
Res::Def(DefKind::Variant, _) => {
- match ty.sty {
+ match ty.kind {
ty::Adt(adt, substs) => {
Some((adt.variant_of_res(def), adt.did, substs))
}
| Res::Def(DefKind::TyAlias, _)
| Res::Def(DefKind::AssocTy, _)
| Res::SelfTy(..) => {
- match ty.sty {
+ match ty.kind {
ty::Adt(adt, substs) if !adt.is_enum() => {
Some((adt.non_enum_variant(), adt.did, substs))
}
self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
// Check bounds on type arguments used in the path.
- let bounds = self.instantiate_bounds(path_span, did, substs);
+ let (bounds, _) = self.instantiate_bounds(path_span, did, substs);
let cause = traits::ObligationCause::new(
path_span,
self.body_id,
QPath::TypeRelative(ref qself, ref segment) => {
let ty = self.to_ty(qself);
- let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.node {
+ let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
path.res
} else {
Res::Err
if let Some(ref init) = local.init {
let init_ty = self.check_decl_initializer(local, &init);
- if init_ty.references_error() {
- self.write_ty(local.hir_id, init_ty);
- }
+ self.overwrite_local_ty_if_err(local, t, init_ty);
}
self.check_pat_top(&local.pat, t, None);
let pat_ty = self.node_ty(local.pat.hir_id);
- if pat_ty.references_error() {
- self.write_ty(local.hir_id, pat_ty);
+ self.overwrite_local_ty_if_err(local, t, pat_ty);
+ }
+
+ fn overwrite_local_ty_if_err(&self, local: &'tcx hir::Local, decl_ty: Ty<'tcx>, ty: Ty<'tcx>) {
+ if ty.references_error() {
+ // Override the types everywhere with `types.err` to avoid knock down errors.
+ self.write_ty(local.hir_id, ty);
+ self.write_ty(local.pat.hir_id, ty);
+ let local_ty = LocalTy {
+ decl_ty,
+ revealed_ty: ty,
+ };
+ self.locals.borrow_mut().insert(local.hir_id, local_ty);
+ self.locals.borrow_mut().insert(local.pat.hir_id, local_ty);
}
}
pub fn check_stmt(&self, stmt: &'tcx hir::Stmt) {
// Don't do all the complex logic below for `DeclItem`.
- match stmt.node {
+ match stmt.kind {
hir::StmtKind::Item(..) => return,
hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
}
self.diverges.set(Diverges::Maybe);
self.has_errors.set(false);
- match stmt.node {
+ match stmt.kind {
hir::StmtKind::Local(ref l) => {
self.check_decl_local(&l);
}
/// // ^^^^ point at this instead of the whole `if` expression
/// ```
fn get_expr_coercion_span(&self, expr: &hir::Expr) -> syntax_pos::Span {
- if let hir::ExprKind::Match(_, arms, _) = &expr.node {
+ if let hir::ExprKind::Match(_, arms, _) = &expr.kind {
let arm_spans: Vec<Span> = arms.iter().filter_map(|arm| {
self.in_progress_tables
.and_then(|tables| tables.borrow().node_type_opt(arm.body.hir_id))
if arm_ty.is_never() {
None
} else {
- Some(match &arm.body.node {
+ Some(match &arm.body.kind {
// Point at the tail expression when possible.
hir::ExprKind::Block(block, _) => block.expr
.as_ref()
//
// #41425 -- label the implicit `()` as being the
// "found type" here, rather than the "expected type".
- if !self.diverges.get().always() {
+ if !self.diverges.get().is_always() {
// #50009 -- Do not point at the entire fn block span, point at the return type
// span, as it is the cause of the requirement, and
// `consider_hint_about_removing_semicolon` will point at the last expression
let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
match node {
Node::Item(&hir::Item {
- node: hir::ItemKind::Fn(_, _, _, body_id), ..
+ kind: hir::ItemKind::Fn(_, _, _, body_id), ..
}) |
Node::ImplItem(&hir::ImplItem {
- node: hir::ImplItemKind::Method(_, body_id), ..
+ kind: hir::ImplItemKind::Method(_, body_id), ..
}) => {
let body = self.tcx.hir().body(body_id);
- if let ExprKind::Block(block, _) = &body.value.node {
+ if let ExprKind::Block(block, _) = &body.value.kind {
return Some(block.span);
}
}
fn get_node_fn_decl(&self, node: Node<'tcx>) -> Option<(&'tcx hir::FnDecl, ast::Ident, bool)> {
match node {
Node::Item(&hir::Item {
- ident, node: hir::ItemKind::Fn(ref decl, ..), ..
+ ident, kind: hir::ItemKind::Fn(ref decl, ..), ..
}) => {
// This is less than ideal, it will not suggest a return type span on any
// method called `main`, regardless of whether it is actually the entry point,
Some((decl, ident, ident.name != sym::main))
}
Node::TraitItem(&hir::TraitItem {
- ident, node: hir::TraitItemKind::Method(hir::MethodSig {
+ ident, kind: hir::TraitItemKind::Method(hir::MethodSig {
ref decl, ..
}, ..), ..
}) => Some((decl, ident, true)),
Node::ImplItem(&hir::ImplItem {
- ident, node: hir::ImplItemKind::Method(hir::MethodSig {
+ ident, kind: hir::ImplItemKind::Method(hir::MethodSig {
ref decl, ..
}, ..), ..
}) => Some((decl, ident, false)),
found: Ty<'tcx>,
) -> bool {
let hir = self.tcx.hir();
- let (def_id, sig) = match found.sty {
+ let (def_id, sig) = match found.kind {
ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
ty::Closure(def_id, substs) => {
// We don't use `closure_sig` to account for malformed closures like
// `|_: [_; continue]| {}` and instead we don't suggest anything.
let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx);
- (def_id, match closure_sig_ty.sty {
+ (def_id, match closure_sig_ty.kind {
ty::FnPtr(sig) => sig,
_ => return false,
})
let mut msg = "call this function";
match hir.get_if_local(def_id) {
Some(Node::Item(hir::Item {
- node: ItemKind::Fn(.., body_id),
+ kind: ItemKind::Fn(.., body_id),
..
})) |
Some(Node::ImplItem(hir::ImplItem {
- node: hir::ImplItemKind::Method(_, body_id),
+ kind: hir::ImplItemKind::Method(_, body_id),
..
})) |
Some(Node::TraitItem(hir::TraitItem {
- node: hir::TraitItemKind::Method(.., hir::TraitMethod::Provided(body_id)),
+ kind: hir::TraitItemKind::Method(.., hir::TraitMethod::Provided(body_id)),
..
})) => {
let body = hir.body(*body_id);
sugg_call = body.params.iter()
- .map(|param| match ¶m.pat.node {
+ .map(|param| match ¶m.pat.kind {
hir::PatKind::Binding(_, _, ident, None)
if ident.name != kw::SelfLower => ident.to_string(),
_ => "_".to_string(),
}).collect::<Vec<_>>().join(", ");
}
Some(Node::Expr(hir::Expr {
- node: ExprKind::Closure(_, _, body_id, closure_span, _),
+ kind: ExprKind::Closure(_, _, body_id, closure_span, _),
span: full_closure_span,
..
})) => {
msg = "call this closure";
let body = hir.body(*body_id);
sugg_call = body.params.iter()
- .map(|param| match ¶m.pat.node {
+ .map(|param| match ¶m.pat.kind {
hir::PatKind::Binding(_, _, ident, None)
if ident.name != kw::SelfLower => ident.to_string(),
_ => "_".to_string(),
}
}
Some(Node::ForeignItem(hir::ForeignItem {
- node: hir::ForeignItemKind::Fn(_, idents, _),
+ kind: hir::ForeignItemKind::Fn(_, idents, _),
..
})) |
Some(Node::TraitItem(hir::TraitItem {
- node: hir::TraitItemKind::Method(.., hir::TraitMethod::Required(idents)),
+ kind: hir::TraitItemKind::Method(.., hir::TraitMethod::Required(idents)),
..
})) => sugg_call = idents.iter()
.map(|ident| if ident.name != kw::SelfLower {
Applicability::MachineApplicable,
);
} else if let (ty::FnDef(def_id, ..), true) = (
- &found.sty,
+ &found.kind,
self.suggest_fn_call(err, expr, expected, found),
) {
if let Some(sp) = self.tcx.hir().span_if_local(*def_id) {
if expected.is_unit() {
// `BlockTailExpression` only relevant if the tail expr would be
// useful on its own.
- match expression.node {
+ match expression.kind {
ExprKind::Call(..) |
ExprKind::MethodCall(..) |
ExprKind::Loop(..) |
(&hir::FunctionRetTy::Return(ref ty), _, _, _) => {
// Only point to return type if the expected type is the return type, as if they
// are not, the expectation must have been caused by something else.
- debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.node);
+ debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
let sp = ty.span;
let ty = AstConv::ast_ty_to_ty(self, ty);
debug!("suggest_missing_return_type: return type {:?}", ty);
debug!("suggest_missing_return_type: expected type {:?}", ty);
- if ty.sty == expected.sty {
+ if ty.kind == expected.kind {
err.span_label(sp, format!("expected `{}` because of return type",
expected));
return true;
// Be helpful when the user wrote `{... expr;}` and
// taking the `;` off is enough to fix the error.
let last_stmt = blk.stmts.last()?;
- let last_expr = match last_stmt.node {
+ let last_expr = match last_stmt.kind {
hir::StmtKind::Semi(ref e) => e,
_ => return None,
};
let ty = self.impl_self_ty(span, impl_def_id).ty;
let adt_def = ty.ty_adt_def();
- match ty.sty {
+ match ty.kind {
ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
let variant = adt_def.non_enum_variant();
let ctor_def_id = variant.ctor_def_id.unwrap();
// First, store the "user substs" for later.
self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
- // Add all the obligations that are required, substituting and
- // normalized appropriately.
- let bounds = self.instantiate_bounds(span, def_id, &substs);
- self.add_obligations_for_parameters(
- traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
- &bounds,
- );
+ self.add_required_obligations(span, def_id, &substs);
// Substitute the values for the type parameters into the type of
// the referenced item.
(ty_substituted, res)
}
+ /// Add all the obligations that are required, substituting and normalized appropriately.
+ fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
+ let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs);
+
+ for (i, mut obligation) in traits::predicates_for_generics(
+ traits::ObligationCause::new(
+ span,
+ self.body_id,
+ traits::ItemObligation(def_id),
+ ),
+ self.param_env,
+ &bounds,
+ ).into_iter().enumerate() {
+ // This makes the error point at the bound, but we want to point at the argument
+ if let Some(span) = spans.get(i) {
+ obligation.cause.code = traits::BindingObligation(def_id, *span);
+ }
+ self.register_predicate(obligation);
+ }
+ }
+
fn check_rustc_args_require_const(&self,
def_id: DefId,
hir_id: hir::HirId,
if let Node::Expr(expr) = self.tcx.hir().get(
self.tcx.hir().get_parent_node(hir_id))
{
- if let ExprKind::Call(ref callee, ..) = expr.node {
+ if let ExprKind::Call(ref callee, ..) = expr.kind {
if callee.hir_id == hir_id {
return
}
while let hir::Node::Expr(parent_expr) =
self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
{
- match &parent_expr.node {
+ match &parent_expr.kind {
hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
if lhs.hir_id == expr_id {
contained_in_place = true;
let mut types_used = vec![false; own_counts.types];
for leaf_ty in ty.walk() {
- if let ty::Param(ty::ParamTy { index, .. }) = leaf_ty.sty {
+ if let ty::Param(ty::ParamTy { index, .. }) = leaf_ty.kind {
debug!("found use of ty param num {}", index);
types_used[index as usize - own_counts.lifetimes] = true;
- } else if let ty::Error = leaf_ty.sty {
+ } else if let ty::Error = leaf_ty.kind {
// If there is already another error, do not emit
// an error for not using a type parameter.
assert!(tcx.sess.has_errors());
}
fn potentially_plural_count(count: usize, word: &str) -> String {
- format!("{} {}{}", count, word, if count == 1 { "" } else { "s" })
+ format!("{} {}{}", count, word, pluralise!(count))
}