]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/check/mod.rs
Auto merge of #57230 - estebank:return-mismatch, r=varkor
[rust.git] / src / librustc_typeck / check / mod.rs
index 39beb2832851b0bf95ff6e18629423290a99c407..772a5b587a36bf54af8dfccb8d59f6bc81644d37 100644 (file)
 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};
@@ -974,10 +975,12 @@ fn visit_local(&mut self, local: &'gcx hir::Local) {
                     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 })
             },
@@ -1302,6 +1305,27 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     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={})",
@@ -1348,7 +1372,16 @@ pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Ite
         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);
@@ -2108,8 +2141,6 @@ pub fn write_field_index(&self, node_id: ast::NodeId, index: usize) {
         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>) {
@@ -2138,23 +2169,27 @@ pub fn write_method_call(&self,
         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);
             }
         }
     }
@@ -2177,41 +2212,47 @@ pub fn write_substs(&self, node_id: hir::HirId, substs: &'tcx Substs<'tcx>) {
     /// 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");
         }
     }
 
@@ -2377,6 +2418,7 @@ pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
 
     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
@@ -2386,8 +2428,9 @@ pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
         // 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
@@ -3422,8 +3465,12 @@ fn check_field(&self,
                         if let Some(suggested_field_name) =
                             Self::suggest_field_name(def.non_enum_variant(),
                                                      &field.as_str(), vec![]) {
-                                err.span_label(field.span,
-                                               format!("did you mean `{}`?", suggested_field_name));
+                                err.span_suggestion_with_applicability(
+                                    field.span,
+                                    "a field with a similar name exists",
+                                    suggested_field_name.to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
                             } else {
                                 err.span_label(field.span, "unknown field");
                                 let struct_variant_def = def.non_enum_variant();
@@ -3550,8 +3597,12 @@ fn report_unknown_field(&self,
         if let Some(field_name) = Self::suggest_field_name(variant,
                                                            &field.ident.as_str(),
                                                            skip_fields.collect()) {
-            err.span_label(field.ident.span,
-                           format!("field does not exist - did you mean `{}`?", field_name));
+            err.span_suggestion_with_applicability(
+                    field.ident.span,
+                    "a field with a similar name exists",
+                    field_name.to_string(),
+                    Applicability::MaybeIncorrect,
+                );
         } else {
             match ty.sty {
                 ty::Adt(adt, ..) => {
@@ -3734,7 +3785,7 @@ pub fn check_struct_path(&self,
         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);
@@ -4421,7 +4472,7 @@ fn check_expr_kind(
                 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
                 }
@@ -4573,6 +4624,7 @@ pub fn resolve_ty_and_def_ufcs<'b>(&self,
                                        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,
@@ -4791,11 +4843,31 @@ fn check_block_with_expected(&self,
                 // #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);
                 }
@@ -4820,59 +4892,81 @@ fn check_block_with_expected(&self,
         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
+    }
 
-            if let Node::Item(&hir::Item {
+    /// 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))
+    }
+
+    /// 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);
@@ -5093,6 +5187,7 @@ pub fn instantiate_value_path(&self,
             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)
@@ -5195,13 +5290,15 @@ pub fn instantiate_value_path(&self,
                         if let Some(adt_def) = adt_def {
                             match adt_def.adt_kind() {
                                 AdtKind::Enum => {
-                                    err.note("did you mean to use one of the enum's variants?");
+                                    err.help("did you mean to use one of the enum's variants?");
                                 },
                                 AdtKind::Struct |
                                 AdtKind::Union => {
-                                    err.span_label(
+                                    err.span_suggestion_with_applicability(
                                         span,
-                                        format!("did you mean `Self {{ /* fields */ }}`?"),
+                                        "use curly brackets",
+                                        String::from("Self { /* fields */ }"),
+                                        Applicability::HasPlaceholders,
                                     );
                                 }
                             }
@@ -5290,7 +5387,7 @@ pub fn instantiate_value_path(&self,
 
         // 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.