Rollup merge of #41939 - eddyb:trait-assoc-const-default, r=petrochenkov

rustc_resolve: don't deny outer type parameters in embedded constants.

This solves a problem noted at https://github.com/rust-lang/rust/issues/29646#issuecomment-300929548, where an associated const default in a trait couldn't refer to `Self` or type parameters, due to inaccuracies in lexical scoping.

I've also allowed "embedded expressions" (`[T; expr]`,  `[x; expr]`, `typeof expr`) to refer to type parameters in scope. *However*, the typesystem still doesn't handle #34344.
Fully resolving that issue requires breaking cycles more aggressively (e.g. lazy evaluation), *even* in when the expression doesn't depend on type parameters, to type-check it at all, and then also type-level "constant projections" (in the vein of `{expr}` from const generics).
This commit is contained in:
Mark Simulacrum 2017-05-13 20:55:10 -06:00 committed by GitHub
commit cfea522226
13 changed files with 74 additions and 51 deletions

View File

@ -1222,27 +1222,26 @@ fn foo() {
"##,
E0435: r##"
A non-constant value was used to initialise a constant.
A non-constant value was used in a constant expression.
Erroneous code example:
```compile_fail,E0435
let foo = 42u32;
const FOO : u32 = foo; // error: attempt to use a non-constant value in a
// constant
let foo = 42;
let a: [u8; foo]; // error: attempt to use a non-constant value in a constant
```
To fix this error, please replace the value with a constant. Example:
```
const FOO : u32 = 42u32; // ok!
let a: [u8; 42]; // ok!
```
Or:
```
const OTHER_FOO : u32 = 42u32;
const FOO : u32 = OTHER_FOO; // ok!
const FOO: usize = 42;
let a: [u8; FOO]; // ok!
```
"##,
@ -1560,7 +1559,7 @@ register_diagnostics! {
// E0157, unused error code
// E0257,
// E0258,
E0402, // cannot use an outer type parameter in this context
// E0402, // cannot use an outer type parameter in this context
// E0406, merged into 420
// E0410, merged into 408
// E0413, merged into 530

View File

@ -127,8 +127,6 @@ impl Ord for BindingError {
enum ResolutionError<'a> {
/// error E0401: can't use type parameters from outer function
TypeParametersFromOuterFunction,
/// error E0402: cannot use an outer type parameter in this context
OuterTypeParameterContext,
/// error E0403: the name is already used for a type parameter in this type parameter list
NameAlreadyUsedInTypeParameterList(Name, &'a Span),
/// error E0407: method is not a member of trait
@ -187,12 +185,6 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
err.span_label(span, "use of type variable from outer function");
err
}
ResolutionError::OuterTypeParameterContext => {
struct_span_err!(resolver.session,
span,
E0402,
"cannot use an outer type parameter in this context")
}
ResolutionError::NameAlreadyUsedInTypeParameterList(name, first_use_span) => {
let mut err = struct_span_err!(resolver.session,
span,
@ -1671,16 +1663,16 @@ impl<'a> Resolver<'a> {
this.check_proc_macro_attrs(&trait_item.attrs);
match trait_item.node {
TraitItemKind::Const(_, ref default) => {
TraitItemKind::Const(ref ty, ref default) => {
this.visit_ty(ty);
// Only impose the restrictions of
// ConstRibKind if there's an actual constant
// ConstRibKind for an actual constant
// expression in a provided default.
if default.is_some() {
if let Some(ref expr) = *default{
this.with_constant_rib(|this| {
visit::walk_trait_item(this, trait_item)
this.visit_expr(expr);
});
} else {
visit::walk_trait_item(this, trait_item)
}
}
TraitItemKind::Method(ref sig, _) => {
@ -1709,9 +1701,13 @@ impl<'a> Resolver<'a> {
});
}
ItemKind::Const(..) | ItemKind::Static(..) => {
self.with_constant_rib(|this| {
visit::walk_item(this, item);
ItemKind::Static(ref ty, _, ref expr) |
ItemKind::Const(ref ty, ref expr) => {
self.with_item_rib(|this| {
this.visit_ty(ty);
this.with_constant_rib(|this| {
this.visit_expr(expr);
});
});
}
@ -1782,13 +1778,21 @@ impl<'a> Resolver<'a> {
self.label_ribs.pop();
}
fn with_item_rib<F>(&mut self, f: F)
where F: FnOnce(&mut Resolver)
{
self.ribs[ValueNS].push(Rib::new(ItemRibKind));
self.ribs[TypeNS].push(Rib::new(ItemRibKind));
f(self);
self.ribs[TypeNS].pop();
self.ribs[ValueNS].pop();
}
fn with_constant_rib<F>(&mut self, f: F)
where F: FnOnce(&mut Resolver)
{
self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind));
self.ribs[TypeNS].push(Rib::new(ConstantItemRibKind));
f(self);
self.ribs[TypeNS].pop();
self.ribs[ValueNS].pop();
}
@ -2755,7 +2759,8 @@ impl<'a> Resolver<'a> {
for rib in ribs {
match rib.kind {
NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) |
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind => {
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
ConstantItemRibKind => {
// Nothing to do. Continue.
}
ItemRibKind => {
@ -2767,14 +2772,6 @@ impl<'a> Resolver<'a> {
}
return Def::Err;
}
ConstantItemRibKind => {
// see #9186
if record_used {
resolve_error(self, span,
ResolutionError::OuterTypeParameterContext);
}
return Def::Err;
}
}
}
}

View File

@ -10,6 +10,6 @@
fn main () {
let foo = 42u32;
const FOO : u32 = foo; //~ ERROR E0435
let _: [u8; foo]; //~ ERROR E0435
//~| NOTE non-constant used with constant
}

View File

@ -26,7 +26,7 @@ impl Foo for Def {
pub fn test<A: Foo, B: Foo>() {
let _array = [4; <A as Foo>::Y];
//~^ ERROR cannot use an outer type parameter in this context [E0402]
//~^ ERROR the trait bound `A: Foo` is not satisfied [E0277]
}
fn main() {

View File

@ -26,7 +26,7 @@ impl Foo for Def {
pub fn test<A: Foo, B: Foo>() {
let _array: [u32; <A as Foo>::Y];
//~^ ERROR cannot use an outer type parameter in this context [E0402]
//~^ ERROR the trait bound `A: Foo` is not satisfied [E0277]
}
fn main() {

View File

@ -14,7 +14,7 @@ enum Bar<T> { What } //~ ERROR parameter `T` is never used
fn foo<T>() {
static a: Bar<T> = Bar::What;
//~^ ERROR cannot use an outer type parameter in this context
//~^ ERROR can't use type parameters from outer function; try using a local type parameter instead
}
fn main() {

View File

@ -11,5 +11,5 @@
fn main() {
let foo = 42u32;
const FOO : u32 = foo;
//~^ ERROR attempt to use a non-constant value in a constant
//~^ ERROR can't capture dynamic environment
}

View File

@ -12,7 +12,7 @@ fn main() {
let foo = 100;
static y: isize = foo + 1;
//~^ ERROR attempt to use a non-constant value in a constant
//~^ ERROR can't capture dynamic environment
println!("{}", y);
}

View File

@ -10,7 +10,7 @@
fn f(x:isize) {
static child: isize = x + 1;
//~^ ERROR attempt to use a non-constant value in a constant
//~^ ERROR can't capture dynamic environment
}
fn main() {}

View File

@ -16,7 +16,7 @@ trait PTrait {
impl PTrait for P {
fn getChildOption(&self) -> Option<Box<P>> {
static childVal: Box<P> = self.child.get();
//~^ ERROR attempt to use a non-constant value in a constant
//~^ ERROR can't capture dynamic environment
panic!();
}
}

View File

@ -0,0 +1,28 @@
// Copyright 2017 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait Dim {
fn dim() -> usize;
}
enum Dim3 {}
impl Dim for Dim3 {
fn dim() -> usize {
3
}
}
fn main() {
let array: [usize; Dim3::dim()]
//~^ ERROR calls in constants are limited to constant functions
= [0; Dim3::dim()];
//~^ ERROR calls in constants are limited to constant functions
}

View File

@ -22,12 +22,7 @@ impl Dim for Dim3 {
pub struct Vector<T, D: Dim> {
entries: [T; D::dim()]
//~^ ERROR cannot use an outer type parameter in this context
//~^ ERROR no associated item named `dim` found for type `D` in the current scope
}
fn main() {
let array: [usize; Dim3::dim()]
//~^ ERROR calls in constants are limited to constant functions
= [0; Dim3::dim()];
//~^ ERROR calls in constants are limited to constant functions
}
fn main() {}

View File

@ -37,6 +37,10 @@ fn sub<A: Foo, B: Foo>() -> i32 {
A::X - B::X
}
trait Bar: Foo {
const Y: i32 = Self::X;
}
fn main() {
assert_eq!(11, Abc::X);
assert_eq!(97, Def::X);