]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/check/mod.rs
Implement RFC 2645 (transparent enums and unions)
[rust.git] / src / librustc_typeck / check / mod.rs
index 7a6d02cc33b210cc3e93d06fa624f1e921d9059b..2e53b380cb71a6b8441b4db009c22d0b424be192 100644 (file)
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_target::spec::abi::Abi;
 use rustc::infer::opaque_types::OpaqueTypeDecl;
-use rustc::infer::type_variable::{TypeVariableOrigin};
+use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc::middle::region;
 use rustc::mir::interpret::{ConstValue, GlobalId};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::{
-    self, AdtKind, CanonicalUserType, Ty, TyCtxt, GenericParamDefKind, Visibility,
+    self, AdtKind, CanonicalUserType, Ty, TyCtxt, Const, GenericParamDefKind, Visibility,
     ToPolyTraitRef, ToPredicate, RegionKind, UserType
 };
 use rustc::ty::adjustment::{
@@ -365,7 +366,12 @@ fn only_has_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
     /// hard constraint exists, creates a fresh type variable.
     fn coercion_target_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> {
         self.only_has_type(fcx)
-            .unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span)))
+            .unwrap_or_else(|| {
+                fcx.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::MiscVariable,
+                    span,
+                })
+            })
     }
 }
 
@@ -518,10 +524,10 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     /// eventually).
     param_env: ty::ParamEnv<'tcx>,
 
-    // Number of errors that had been reported when we started
-    // checking this function. On exit, if we find that *more* errors
-    // have been reported, we will skip regionck and other work that
-    // expects the types within the function to be consistent.
+    /// Number of errors that had been reported when we started
+    /// checking this function. On exit, if we find that *more* errors
+    /// have been reported, we will skip regionck and other work that
+    /// expects the types within the function to be consistent.
     err_count_on_creation: usize,
 
     ret_coercion: Option<RefCell<DynamicCoerceMany<'gcx, 'tcx>>>,
@@ -930,7 +936,10 @@ fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>)
         match ty_opt {
             None => {
                 // infer the variable's type
-                let var_ty = self.fcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
+                let var_ty = self.fcx.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::TypeInference,
+                    span,
+                });
                 self.fcx.locals.borrow_mut().insert(nid, LocalTy {
                     decl_ty: var_ty,
                     revealed_ty: var_ty
@@ -1009,16 +1018,6 @@ fn visit_pat(&mut self, p: &'gcx hir::Pat) {
     // Don't descend into the bodies of nested closures
     fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
                 _: hir::BodyId, _: Span, _: hir::HirId) { }
-
-    fn visit_argument_source(&mut self, s: &'gcx hir::ArgSource) {
-        match s {
-            // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
-            // a `NodeId` w/out a type, as it is only used for getting the name of the original
-            // pattern for diagnostics where only an `hir::Arg` is present.
-            hir::ArgSource::AsyncFn(..) => {},
-            _ => intravisit::walk_argument_source(self, s),
-        }
-    }
 }
 
 /// When `check_fn` is invoked on a generator (i.e., a body that
@@ -1074,7 +1073,10 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     let span = body.value.span;
 
     if body.is_generator && can_be_generator.is_some() {
-        let yield_ty = fcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
+        let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::TypeInference,
+            span,
+        });
         fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
         fcx.yield_ty = Some(yield_ty);
     }
@@ -1108,7 +1110,10 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     // This ensures that all nested generators appear before the entry of this generator.
     // resolve_generator_interiors relies on this property.
     let gen_ty = if can_be_generator.is_some() && body.is_generator {
-        let interior = fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span));
+        let interior = fcx.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::MiscVariable,
+            span,
+        });
         fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior));
         Some(GeneratorTypes {
             yield_ty: fcx.yield_ty.unwrap(),
@@ -1146,7 +1151,11 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     let mut actual_return_ty = coercion.complete(&fcx);
     if actual_return_ty.is_never() {
         actual_return_ty = fcx.next_diverging_ty_var(
-            TypeVariableOrigin::DivergingFn(span));
+            TypeVariableOrigin {
+                kind: TypeVariableOriginKind::DivergingFn,
+                span,
+            },
+        );
     }
     fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
 
@@ -1301,7 +1310,7 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let def = tcx.adt_def(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
     check_representable(tcx, span, def_id);
-
+    check_transparent(tcx, span, def_id);
     check_packed(tcx, span, def_id);
 }
 
@@ -1798,8 +1807,43 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De
         return;
     }
 
+    if adt.is_enum() {
+        if !tcx.features().transparent_enums {
+            emit_feature_err(&tcx.sess.parse_sess,
+                             sym::transparent_enums,
+                             sp,
+                             GateIssue::Language,
+                             "transparent enums are unstable");
+        }
+        if adt.variants.len() != 1 {
+            let variant_spans: Vec<_> = adt.variants.iter().map(|variant| {
+                tcx.hir().span_if_local(variant.def_id).unwrap()
+            }).collect();
+            let mut err = struct_span_err!(tcx.sess, sp, E0731,
+                            "transparent enum needs exactly one variant, but has {}",
+                            adt.variants.len());
+            if !variant_spans.is_empty() {
+                err.span_note(variant_spans, &format!("the following variants exist on `{}`",
+                                                      tcx.def_path_str(def_id)));
+            }
+            err.emit();
+            if adt.variants.is_empty() {
+                // Don't bother checking the fields. No variants (and thus no fields) exist.
+                return;
+            }
+        }
+    }
+
+    if adt.is_union() && !tcx.features().transparent_unions {
+        emit_feature_err(&tcx.sess.parse_sess,
+                         sym::transparent_unions,
+                         sp,
+                         GateIssue::Language,
+                         "transparent unions are unstable");
+    }
+
     // For each field, figure out if it's known to be a ZST and align(1)
-    let field_infos = adt.non_enum_variant().fields.iter().map(|field| {
+    let field_infos = adt.all_fields().map(|field| {
         let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
         let param_env = tcx.param_env(field.did);
         let layout = tcx.layout_of(param_env.and(ty));
@@ -1814,16 +1858,24 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De
     let non_zst_count = non_zst_fields.clone().count();
     if non_zst_count != 1 {
         let field_spans: Vec<_> = non_zst_fields.map(|(span, _zst, _align1)| span).collect();
-        struct_span_err!(tcx.sess, sp, E0690,
-                         "transparent struct needs exactly one non-zero-sized field, but has {}",
-                         non_zst_count)
-        .span_note(field_spans, "non-zero-sized field")
-        .emit();
+
+        let mut err = struct_span_err!(tcx.sess, sp, E0690,
+                         "{}transparent {} needs exactly one non-zero-sized field, but has {}",
+                         if adt.is_enum() { "the variant of a " } else { "" },
+                         adt.descr(),
+                         non_zst_count);
+        if !field_spans.is_empty() {
+            err.span_note(field_spans,
+                          &format!("the following non-zero-sized fields exist on `{}`:",
+                                   tcx.def_path_str(def_id)));
+        }
+        err.emit();
     }
     for (span, zst, align1) in field_infos {
         if zst && !align1 {
             span_err!(tcx.sess, span, E0691,
-                      "zero-sized field in transparent struct has alignment larger than 1");
+                      "zero-sized field in transparent {} has alignment larger than 1",
+                      adt.descr());
         }
     }
 }
@@ -1890,6 +1942,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     check_representable(tcx, sp, def_id);
+    check_transparent(tcx, sp, def_id);
 }
 
 fn report_unexpected_variant_res<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
@@ -1930,8 +1983,11 @@ fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
         })
     }
 
-    fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>)
-                -> Option<ty::Region<'tcx>> {
+    fn re_infer(
+        &self,
+        def: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> Option<ty::Region<'tcx>> {
         let v = match def {
             Some(def) => infer::EarlyBoundRegion(span, def.name),
             None => infer::MiscVariable(span)
@@ -1939,17 +1995,37 @@ fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>)
         Some(self.next_region_var(v))
     }
 
-    fn ty_infer(&self, span: Span) -> Ty<'tcx> {
-        self.next_ty_var(TypeVariableOrigin::TypeInference(span))
+    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() {
+                return ty;
+            }
+            unreachable!()
+        } else {
+            self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::TypeInference,
+                span,
+            })
+        }
     }
 
-    fn ty_infer_for_def(&self,
-                        ty_param_def: &ty::GenericParamDef,
-                        span: Span) -> Ty<'tcx> {
-        if let UnpackedKind::Type(ty) = self.var_for_def(span, ty_param_def).unpack() {
-            return ty;
+    fn ct_infer(
+        &self,
+        ty: Ty<'tcx>,
+        param: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> &'tcx Const<'tcx> {
+        if let Some(param) = param {
+            if let UnpackedKind::Const(ct) = self.var_for_def(span, param).unpack() {
+                return ct;
+            }
+            unreachable!()
+        } else {
+            self.next_const_var(ty, ConstVariableOrigin {
+                kind: ConstVariableOriginKind::ConstInference,
+                span,
+            })
         }
-        unreachable!()
     }
 
     fn projected_ty_from_poly_trait_ref(&self,
@@ -2648,7 +2724,10 @@ fn try_index_step(&self,
             // If some lookup succeeds, write callee into table and extract index/element
             // type from the method signature.
             // If some lookup succeeded, install method in table
-            let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span));
+            let input_ty = self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::AutoDeref,
+                span: base_expr.span,
+            });
             let method = self.try_overloaded_place_op(
                 expr.span, self_ty, &[input_ty], needs, PlaceOp::Index);
 
@@ -3146,7 +3225,11 @@ fn check_expr_meets_expectation_or_error(&self,
             assert!(!self.tables.borrow().adjustments().contains_key(expr.hir_id),
                     "expression with never type wound up being adjusted");
             let adj_ty = self.next_diverging_ty_var(
-                TypeVariableOrigin::AdjustmentType(expr.span));
+                TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::AdjustmentType,
+                    span: expr.span,
+                },
+            );
             self.apply_adjustments(expr, vec![Adjustment {
                 kind: Adjust::NeverToAny,
                 target: adj_ty
@@ -4372,8 +4455,12 @@ fn check_expr_kind(
                 });
 
                 let element_ty = if !args.is_empty() {
-                    let coerce_to = uty.unwrap_or_else(
-                        || self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)));
+                    let coerce_to = uty.unwrap_or_else(|| {
+                        self.next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::TypeInference,
+                            span: expr.span,
+                        })
+                    });
                     let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args);
                     assert_eq!(self.diverges.get(), Diverges::Maybe);
                     for e in args {
@@ -4383,7 +4470,10 @@ fn check_expr_kind(
                     }
                     coerce.complete(self)
                 } else {
-                    self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))
+                    self.next_ty_var(TypeVariableOrigin {
+                        kind: TypeVariableOriginKind::TypeInference,
+                        span: expr.span,
+                    })
                 };
                 tcx.mk_array(element_ty, args.len() as u64)
             }
@@ -4419,7 +4509,10 @@ fn check_expr_kind(
                         (uty, uty)
                     }
                     None => {
-                        let ty = self.next_ty_var(TypeVariableOrigin::MiscVariable(element.span));
+                        let ty = self.next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::MiscVariable,
+                            span: element.span,
+                        });
                         let element_ty = self.check_expr_has_type_or_error(&element, ty);
                         (element_ty, ty)
                     }
@@ -5264,7 +5357,7 @@ pub fn instantiate_value_path(&self,
             Err(ErrorReported) => return (tcx.types.err, res),
         };
         let path_segs = match res {
-            Res::Local(_) | Res::Upvar(..) => Vec::new(),
+            Res::Local(_) => vec![],
             Res::Def(kind, def_id) =>
                 AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id),
             _ => bug!("instantiate_value_path on {:?}", res),
@@ -5325,14 +5418,11 @@ pub fn instantiate_value_path(&self,
             }
         }));
 
-        match res {
-            Res::Local(hid) | Res::Upvar(hid, ..) => {
-                let ty = self.local_ty(span, hid).decl_ty;
-                let ty = self.normalize_associated_types_in(span, &ty);
-                self.write_ty(hir_id, ty);
-                return (ty, res);
-            }
-            _ => {}
+        if let Res::Local(hid) = res {
+            let ty = self.local_ty(span, hid).decl_ty;
+            let ty = self.normalize_associated_types_in(span, &ty);
+            self.write_ty(hir_id, ty);
+            return (ty, res);
         }
 
         if generics_has_err {
@@ -5394,10 +5484,10 @@ pub fn instantiate_value_path(&self,
                     if !infer_args_for_err.contains(&index) {
                         // Check whether the user has provided generic arguments.
                         if let Some(ref data) = segments[index].args {
-                            return (Some(data), segments[index].infer_types);
+                            return (Some(data), segments[index].infer_args);
                         }
                     }
-                    return (None, segments[index].infer_types);
+                    return (None, segments[index].infer_args);
                 }
 
                 (None, true)
@@ -5418,13 +5508,13 @@ pub fn instantiate_value_path(&self,
                 }
             },
             // Provide substitutions for parameters for which arguments are inferred.
-            |substs, param, infer_types| {
+            |substs, param, infer_args| {
                 match param.kind {
                     GenericParamDefKind::Lifetime => {
-                        self.re_infer(span, Some(param)).unwrap().into()
+                        self.re_infer(Some(param), span).unwrap().into()
                     }
                     GenericParamDefKind::Type { has_default, .. } => {
-                        if !infer_types && has_default {
+                        if !infer_args && has_default {
                             // If we have a default, then we it doesn't matter that we're not
                             // inferring the type arguments: we provide the default where any
                             // is missing.