diff --git a/src/librustc_mir/borrow_check/nll/region_infer/annotation.rs b/src/librustc_mir/borrow_check/nll/region_infer/annotation.rs index e8a23acd798de..d213f376d2bca 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/annotation.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/annotation.rs @@ -45,10 +45,11 @@ impl<'gcx, 'tcx> RegionInferenceContext<'tcx> { &substs[..] )); } - DefiningTy::Const(ty) => { + DefiningTy::Const(def_id, substs) => { err.note(&format!( - "defining type: {:?}", - ty + "defining constant type: {:?} with substs {:#?}", + def_id, + &substs[..] )); } } diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index e47e3c728dff2..668172749fecb 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -125,7 +125,7 @@ pub enum DefiningTy<'tcx> { /// The MIR represents some form of constant. The signature then /// is that it has no inputs and a single return value, which is /// the value of the constant. - Const(Ty<'tcx>), + Const(DefId, &'tcx Substs<'tcx>), } #[derive(Debug)] @@ -534,34 +534,42 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { /// see `DefiningTy` for details. fn defining_ty(&self) -> DefiningTy<'tcx> { let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id); - let defining_ty = if self.mir_def_id == closure_base_def_id { - tcx.type_of(closure_base_def_id) - } else { - let tables = tcx.typeck_tables_of(self.mir_def_id); - tables.node_id_to_type(self.mir_hir_id) - }; - - let defining_ty = self.infcx - .replace_free_regions_with_nll_infer_vars(FR, &defining_ty); - match tcx.hir.body_owner_kind(self.mir_node_id) { - BodyOwnerKind::Fn => match defining_ty.sty { - ty::TyClosure(def_id, substs) => DefiningTy::Closure(def_id, substs), - ty::TyGenerator(def_id, substs, interior) => { - DefiningTy::Generator(def_id, substs, interior) + BodyOwnerKind::Fn => { + let defining_ty = if self.mir_def_id == closure_base_def_id { + tcx.type_of(closure_base_def_id) + } else { + let tables = tcx.typeck_tables_of(self.mir_def_id); + tables.node_id_to_type(self.mir_hir_id) + }; + + let defining_ty = self.infcx + .replace_free_regions_with_nll_infer_vars(FR, &defining_ty); + + match defining_ty.sty { + ty::TyClosure(def_id, substs) => DefiningTy::Closure(def_id, substs), + ty::TyGenerator(def_id, substs, interior) => { + DefiningTy::Generator(def_id, substs, interior) + } + ty::TyFnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs), + _ => span_bug!( + tcx.def_span(self.mir_def_id), + "expected defining type for `{:?}`: `{:?}`", + self.mir_def_id, + defining_ty + ), } - ty::TyFnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs), - _ => span_bug!( - tcx.def_span(self.mir_def_id), - "expected defining type for `{:?}`: `{:?}`", - self.mir_def_id, - defining_ty - ), - }, - BodyOwnerKind::Const | BodyOwnerKind::Static(..) => DefiningTy::Const(defining_ty), + } + + BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { + assert_eq!(closure_base_def_id, self.mir_def_id); + let identity_substs = Substs::identity_for_item(tcx, closure_base_def_id); + let substs = self.infcx + .replace_free_regions_with_nll_infer_vars(FR, &identity_substs); + DefiningTy::Const(self.mir_def_id, substs) + } } } @@ -592,13 +600,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { substs.substs } - DefiningTy::FnDef(_, substs) => substs, - - // When we encounter a constant body, just return whatever - // substitutions are in scope for that constant. - DefiningTy::Const(_) => { - identity_substs - } + DefiningTy::FnDef(_, substs) | DefiningTy::Const(_, substs) => substs, }; let global_mapping = iter::once((gcx.types.re_static, fr_static)); @@ -660,9 +662,14 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { sig.inputs_and_output() } - // For a constant body, there are no inputs, and one - // "output" (the type of the constant). - DefiningTy::Const(ty) => ty::Binder::dummy(tcx.mk_type_list(iter::once(ty))), + DefiningTy::Const(def_id, _) => { + // For a constant body, there are no inputs, and one + // "output" (the type of the constant). + assert_eq!(self.mir_def_id, def_id); + let ty = tcx.type_of(def_id); + let ty = indices.fold_to_region_vids(tcx, &ty); + ty::Binder::dummy(tcx.mk_type_list(iter::once(ty))) + } } } diff --git a/src/test/ui/nll/trait-associated-constant.rs b/src/test/ui/nll/trait-associated-constant.rs new file mode 100644 index 0000000000000..b0f5fbf7160d1 --- /dev/null +++ b/src/test/ui/nll/trait-associated-constant.rs @@ -0,0 +1,42 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test cases where we put various lifetime constraints on trait +// associated constants. + +#![feature(rustc_attrs)] + +use std::option::Option; + +trait Anything<'a: 'b, 'b> { + const AC: Option<&'b str>; +} + +struct OKStruct { } + +impl<'a: 'b, 'b> Anything<'a, 'b> for OKStruct { + const AC: Option<&'b str> = None; +} + +struct FailStruct1 { } + +impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 { + const AC: Option<&'c str> = None; + //~^ ERROR: mismatched types +} + +struct FailStruct2 { } + +impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 { + const AC: Option<&'a str> = None; + //~^ ERROR: mismatched types +} + +fn main() {} diff --git a/src/test/ui/nll/trait-associated-constant.stderr b/src/test/ui/nll/trait-associated-constant.stderr new file mode 100644 index 0000000000000..100e3362886b3 --- /dev/null +++ b/src/test/ui/nll/trait-associated-constant.stderr @@ -0,0 +1,52 @@ +error[E0308]: mismatched types + --> $DIR/trait-associated-constant.rs:31:5 + | +31 | const AC: Option<&'c str> = None; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected type `std::option::Option<&'b str>` + found type `std::option::Option<&'c str>` +note: the lifetime 'c as defined on the impl at 30:1... + --> $DIR/trait-associated-constant.rs:30:1 + | +30 | / impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 { +31 | | const AC: Option<&'c str> = None; +32 | | //~^ ERROR: mismatched types +33 | | } + | |_^ +note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 30:1 + --> $DIR/trait-associated-constant.rs:30:1 + | +30 | / impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 { +31 | | const AC: Option<&'c str> = None; +32 | | //~^ ERROR: mismatched types +33 | | } + | |_^ + +error[E0308]: mismatched types + --> $DIR/trait-associated-constant.rs:38:5 + | +38 | const AC: Option<&'a str> = None; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected type `std::option::Option<&'b str>` + found type `std::option::Option<&'a str>` +note: the lifetime 'a as defined on the impl at 37:1... + --> $DIR/trait-associated-constant.rs:37:1 + | +37 | / impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 { +38 | | const AC: Option<&'a str> = None; +39 | | //~^ ERROR: mismatched types +40 | | } + | |_^ +note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 37:1 + --> $DIR/trait-associated-constant.rs:37:1 + | +37 | / impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 { +38 | | const AC: Option<&'a str> = None; +39 | | //~^ ERROR: mismatched types +40 | | } + | |_^ + +error: aborting due to 2 previous errors +