use rustc::middle::region;
use rustc::mir::interpret::{ConstValue, GlobalId};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
-use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, RegionKind, Visibility,
- ToPolyTraitRef, ToPredicate};
+use rustc::ty::{
+ self, AdtKind, CanonicalUserTypeAnnotation, Ty, TyCtxt, GenericParamDefKind, Visibility,
+ ToPolyTraitRef, ToPredicate, RegionKind, UserTypeAnnotation
+};
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::query::Providers;
-use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
- UserSelfTy, UserSubsts};
+use rustc::ty::subst::{UnpackedKind, Subst, Substs, UserSelfTy, UserSubsts};
use rustc::ty::util::{Representability, IntTypeExt, Discr};
use rustc::ty::layout::VariantIdx;
use syntax_pos::{self, BytePos, Span, MultiSpan};
o_ty
};
- let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(&revealed_ty);
+ let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(
+ &UserTypeAnnotation::Ty(revealed_ty)
+ );
debug!("visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
ty.hir_id, o_ty, revealed_ty, c_ty);
- self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty);
+ self.fcx.tables.borrow_mut().user_provided_types_mut().insert(ty.hir_id, c_ty);
Some(LocalTy { decl_ty: o_ty, revealed_ty })
},
check_packed(tcx, span, def_id);
}
+fn check_opaque<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId,
+ substs: &'tcx Substs<'tcx>,
+ span: Span,
+) {
+ if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) {
+ let mut err = struct_span_err!(
+ tcx.sess, span, E0720,
+ "opaque type expands to a recursive type",
+ );
+ err.span_label(span, "expands to self-referential type");
+ if let ty::Opaque(..) = partially_expanded_type.sty {
+ err.note("type resolves to itself");
+ } else {
+ err.note(&format!("expanded type is `{}`", partially_expanded_type));
+ }
+ err.emit();
+ }
+}
+
pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
debug!(
"check_item_type(it.id={}, it.name={})",
hir::ItemKind::Union(..) => {
check_union(tcx, it.id, it.span);
}
- hir::ItemKind::Existential(..) | hir::ItemKind::Ty(..) => {
+ hir::ItemKind::Existential(..) => {
+ let def_id = tcx.hir().local_def_id(it.id);
+ let pty_ty = tcx.type_of(def_id);
+ let generics = tcx.generics_of(def_id);
+
+ check_bounds_are_used(tcx, &generics, pty_ty);
+ let substs = Substs::identity_for_item(tcx, def_id);
+ check_opaque(tcx, def_id, substs, it.span);
+ }
+ hir::ItemKind::Ty(..) => {
let def_id = tcx.hir().local_def_id(it.id);
let pty_ty = tcx.type_of(def_id);
let generics = tcx.generics_of(def_id);
self.tables.borrow_mut().field_indices_mut().insert(hir_id, index);
}
- // The NodeId and the ItemLocalId must identify the same item. We just pass
- // both of them for consistency checking.
pub fn write_method_call(&self,
hir_id: hir::HirId,
method: MethodCallee<'tcx>) {
if !method.substs.is_noop() {
let method_generics = self.tcx.generics_of(method.def_id);
if !method_generics.params.is_empty() {
- let user_substs = self.infcx.probe(|_| {
- let just_method_substs = Substs::for_item(self.tcx, method.def_id, |param, _| {
- let i = param.index as usize;
- if i < method_generics.parent_count {
- self.infcx.var_for_def(DUMMY_SP, param)
- } else {
- method.substs[i]
- }
- });
- self.infcx.canonicalize_user_type_annotation(&UserSubsts {
- substs: just_method_substs,
+ let user_type_annotation = self.infcx.probe(|_| {
+ let user_substs = UserSubsts {
+ substs: Substs::for_item(self.tcx, method.def_id, |param, _| {
+ let i = param.index as usize;
+ if i < method_generics.parent_count {
+ self.infcx.var_for_def(DUMMY_SP, param)
+ } else {
+ method.substs[i]
+ }
+ }),
user_self_ty: None, // not relevant here
- })
+ };
+
+ self.infcx.canonicalize_user_type_annotation(&UserTypeAnnotation::TypeOf(
+ method.def_id,
+ user_substs,
+ ))
});
- debug!("write_method_call: user_substs = {:?}", user_substs);
- self.write_user_substs(hir_id, user_substs);
+ debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
+ self.write_user_type_annotation(hir_id, user_type_annotation);
}
}
}
/// This should be invoked **before any unifications have
/// occurred**, so that annotations like `Vec<_>` are preserved
/// properly.
- pub fn write_user_substs_from_substs(
+ pub fn write_user_type_annotation_from_substs(
&self,
hir_id: hir::HirId,
+ def_id: DefId,
substs: &'tcx Substs<'tcx>,
user_self_ty: Option<UserSelfTy<'tcx>>,
) {
debug!(
- "write_user_substs_from_substs({:?}, {:?}) in fcx {}",
- hir_id,
- substs,
- self.tag(),
+ "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \
+ user_self_ty={:?} in fcx {}",
+ hir_id, def_id, substs, user_self_ty, self.tag(),
);
if !substs.is_noop() {
- let user_substs = self.infcx.canonicalize_user_type_annotation(&UserSubsts {
- substs,
- user_self_ty,
- });
- debug!("instantiate_value_path: user_substs = {:?}", user_substs);
- self.write_user_substs(hir_id, user_substs);
+ let canonicalized = self.infcx.canonicalize_user_type_annotation(
+ &UserTypeAnnotation::TypeOf(def_id, UserSubsts {
+ substs,
+ user_self_ty,
+ })
+ );
+ debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized);
+ self.write_user_type_annotation(hir_id, canonicalized);
}
}
- pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalUserSubsts<'tcx>) {
+ pub fn write_user_type_annotation(
+ &self,
+ hir_id: hir::HirId,
+ canonical_user_type_annotation: CanonicalUserTypeAnnotation<'tcx>,
+ ) {
debug!(
- "write_user_substs({:?}, {:?}) in fcx {}",
- hir_id,
- substs,
- self.tag(),
+ "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
+ hir_id, canonical_user_type_annotation, self.tag(),
);
- if !substs.is_identity() {
- self.tables.borrow_mut().user_substs_mut().insert(hir_id, substs);
+ if !canonical_user_type_annotation.is_identity() {
+ self.tables.borrow_mut().user_provided_types_mut().insert(
+ hir_id, canonical_user_type_annotation
+ );
} else {
- debug!("write_user_substs: skipping identity substs");
+ debug!("write_user_type_annotation: skipping identity substs");
}
}
pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
let ty = self.to_ty(ast_ty);
+ debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
// If the type given by the user has free regions, save it for
// later, since NLL would like to enforce those. Also pass in
// although I have my doubts). Other sorts of things are
// already sufficiently enforced with erased regions. =)
if ty.has_free_regions() || ty.has_projections() {
- let c_ty = self.infcx.canonicalize_response(&ty);
- self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty);
+ let c_ty = self.infcx.canonicalize_response(&UserTypeAnnotation::Ty(ty));
+ debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
+ self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
}
ty
if let Some((variant, did, substs)) = variant {
debug!("check_struct_path: did={:?} substs={:?}", did, substs);
let hir_id = self.tcx.hir().node_to_hir_id(node_id);
- self.write_user_substs_from_substs(hir_id, substs, None);
+ 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);
if element_ty.references_error() {
tcx.types.err
} else if let Ok(count) = count {
- tcx.mk_ty(ty::Array(t, count))
+ tcx.mk_ty(ty::Array(t, tcx.intern_lazy_const(ty::LazyConst::Evaluated(count))))
} else {
tcx.types.err
}
span: Span)
-> (Def, Option<Ty<'tcx>>, &'b [hir::PathSegment])
{
+ debug!("resolve_ty_and_def_ufcs: qpath={:?} node_id={:?} span={:?}", qpath, node_id, span);
let (ty, qself, item_segment) = match *qpath {
QPath::Resolved(ref opt_qself, ref path) => {
return (path.def,
// #41425 -- label the implicit `()` as being the
// "found type" here, rather than the "expected type".
if !self.diverges.get().always() {
- coerce.coerce_forced_unit(self, &self.misc(blk.span), &mut |err| {
+ // #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
+ // if it were a relevant part of the error. This improves usability in editors
+ // that highlight errors inline.
+ let mut sp = blk.span;
+ let mut fn_span = None;
+ if let Some((decl, ident)) = self.get_parent_fn_decl(blk.id) {
+ let ret_sp = decl.output.span();
+ if let Some(block_sp) = self.parent_item_span(blk.id) {
+ // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
+ // output would otherwise be incorrect and even misleading. Make sure
+ // the span we're aiming at correspond to a `fn` body.
+ if block_sp == blk.span {
+ sp = ret_sp;
+ fn_span = Some(ident.span);
+ }
+ }
+ }
+ coerce.coerce_forced_unit(self, &self.misc(sp), &mut |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
- self.consider_hint_about_removing_semicolon(blk,
- expected_ty,
- err);
+ self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
+ }
+ if let Some(fn_span) = fn_span {
+ err.span_label(fn_span, "this function's body doesn't return");
}
}, false);
}
ty
}
- /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
- /// suggestion can be made, `None` otherwise.
- pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
- // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
- // `while` before reaching it, as block tail returns are not available in them.
- if let Some(fn_id) = self.tcx.hir().get_return_block(blk_id) {
- let parent = self.tcx.hir().get(fn_id);
+ fn parent_item_span(&self, id: ast::NodeId) -> Option<Span> {
+ let node = self.tcx.hir().get(self.tcx.hir().get_parent(id));
+ match node {
+ Node::Item(&hir::Item {
+ node: hir::ItemKind::Fn(_, _, _, body_id), ..
+ }) |
+ Node::ImplItem(&hir::ImplItem {
+ node: hir::ImplItemKind::Method(_, body_id), ..
+ }) => {
+ let body = self.tcx.hir().body(body_id);
+ if let ExprKind::Block(block, _) = &body.value.node {
+ return Some(block.span);
+ }
+ }
+ _ => {}
+ }
+ None
+ }
+
+ /// Given a function block's `NodeId`, return its `FnDecl` if it exists, or `None` otherwise.
+ fn get_parent_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, ast::Ident)> {
+ let parent = self.tcx.hir().get(self.tcx.hir().get_parent(blk_id));
+ self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
+ }
- if let Node::Item(&hir::Item {
+ /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
+ fn get_node_fn_decl(&self, node: Node) -> Option<(hir::FnDecl, ast::Ident, bool)> {
+ match node {
+ Node::Item(&hir::Item {
ident, node: hir::ItemKind::Fn(ref decl, ..), ..
- }) = parent {
- decl.clone().and_then(|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,
- // but it will still present it as the reason for the expected type.
- Some((decl, ident.name != Symbol::intern("main")))
- })
- } else if let Node::TraitItem(&hir::TraitItem {
- node: hir::TraitItemKind::Method(hir::MethodSig {
+ }) => decl.clone().and_then(|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,
+ // but it will still present it as the reason for the expected type.
+ Some((decl, ident, ident.name != Symbol::intern("main")))
+ }),
+ Node::TraitItem(&hir::TraitItem {
+ ident, node: hir::TraitItemKind::Method(hir::MethodSig {
ref decl, ..
}, ..), ..
- }) = parent {
- decl.clone().and_then(|decl| {
- Some((decl, true))
- })
- } else if let Node::ImplItem(&hir::ImplItem {
- node: hir::ImplItemKind::Method(hir::MethodSig {
+ }) => decl.clone().and_then(|decl| Some((decl, ident, true))),
+ Node::ImplItem(&hir::ImplItem {
+ ident, node: hir::ImplItemKind::Method(hir::MethodSig {
ref decl, ..
}, ..), ..
- }) = parent {
- decl.clone().and_then(|decl| {
- Some((decl, false))
- })
- } else {
- None
- }
- } else {
- None
+ }) => decl.clone().and_then(|decl| Some((decl, ident, false))),
+ _ => None,
}
}
+ /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
+ /// suggestion can be made, `None` otherwise.
+ pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
+ // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
+ // `while` before reaching it, as block tail returns are not available in them.
+ self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
+ let parent = self.tcx.hir().get(blk_id);
+ self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
+ })
+ }
+
/// On implicit return expressions with mismatched types, provide the following suggestions:
///
/// - Point out the method's return type as the reason for the expected type
/// - Possible missing semicolon
/// - Possible missing return type if the return type is the default, and not `fn main()`
- pub fn suggest_mismatched_types_on_tail(&self,
- err: &mut DiagnosticBuilder<'tcx>,
- expression: &'gcx hir::Expr,
- expected: Ty<'tcx>,
- found: Ty<'tcx>,
- cause_span: Span,
- blk_id: ast::NodeId) {
+ pub fn suggest_mismatched_types_on_tail(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ expression: &'gcx hir::Expr,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ cause_span: Span,
+ blk_id: ast::NodeId,
+ ) {
self.suggest_missing_semicolon(err, expression, expected, cause_span);
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
Def::Method(def_id) |
Def::AssociatedConst(def_id) => {
let container = tcx.associated_item(def_id).container;
+ debug!("instantiate_value_path: def={:?} container={:?}", def, container);
match container {
ty::TraitContainer(trait_did) => {
callee::check_legal_trait_for_method_call(tcx, span, trait_did)
// First, store the "user substs" for later.
let hir_id = tcx.hir().node_to_hir_id(node_id);
- self.write_user_substs_from_substs(hir_id, substs, user_self_ty);
+ 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.