Closed brendanzab closed 11 years ago
It's an incompleteness, a bug. We're intending to support integer constant expressions in that context eventually. I'd pull up the github issue associated with it but their search engine fell over yesterday and still doesn't have indices back online. Will check again next time around.
It would also be swell to allow values like enum discriminants, which would allow things like
enum A {
A1,
A2,
A_Count
}
let foo: [int * A_Count];
Regarding the enum trick, I'd prefer to have some way of getting the max discriminant of an enum. I do this trick of adding an extra value in C all the time but it's annoying because it foils exhaustiveness checks.
So I have a patch that addresses this, problem is that it only half works. Simple constant expressions like 2*3
or 32/2
work but attempting to use a previously defined constant fails (Non-constant path in constant expr
). This seems to be because const_eval::eval_const_expr
can't find the expr in the def_map
when called in typeck::astconv
. I'm not sure about order of things in that stage of the compiler so I'm a bit lost in how to approach this.
It looks the astconv stuff might happen in the collect pass, which directly precedes the resolve pass which does record information about constants in def_map.
So trying to avoid the const_eval in astconv by propagating @ast::expr
down through ty::vstore_fixed
doesn't work since it necessitates creating expr
in various places in trans which results in errors like
expected `[u8]/8` but found `[u8]/8` ([] storage differs: expected 8 but found 8)
Thanks to some help from pcwalton, I have this working properly now.
@pcwalton @graydon regarding the set of expressions that can be included in constants, I think there are issues around field projection and the like because we need to evaluate constants during the "collect" of type checking.
That is, type checking first iterates over all struct declarations and converts them into types. It then descends into function bodies and expressions to check those. The tricky part here is that checking a function body / expression requires the types for the struct declarations and so forth. In particular, imagine we have to type check something like x.f
--- we need to compute the type of x
, but if it has a struct type, for example, we need to lookup that struct and figure out the declared type of the field f
. Right now the code that type checks a constant expression is the same as the code that type checks a function body, so it e.g. assumes that the types of structs are available.
Basically this means that either the code that type checks expressions will have to be parameterized over what phase it is operating in (hard and annoying but not impossible), or else we will wind up having to duplicate the code that type checks constants so that when we are evaluating constants to compute the final types we don't require that type conversion has taken place.
Thus far we have taken the duplication path. If you look in eval_const.rs
, you will see there that the function which evaluates constants basically duplicates the type rules, which is fine because it adds additional logic. You'll also see that it aborts for things like field projection. So in essence we already have established a subset of constant expressions, though I don't think failure is handled gracefully.
If we are duplicating, it makes sense from a practical perspective to duplicate as little as possible. Duplicating integer arithmetic and so on seems pretty straightforward. I am not sure though if there is a theoretical reason that we can't handle more complex expressions, but the logic involved is fairly complex (think autoderef etc).
It is not really clear to me when it is necessary to have field projection (a.b
), pointer dereferences (*a
), indexing (a[b]
) in constant expressions. I feel like any example that makes use of such things can be written more clearly by having an intermediate constant for the value you are trying to obtain.
Does this make sense?
The original issue as described was resolved by #5112. There appears to be some remaining questions of how expressive we should allow constant expressions to be, but I do not think this ticket is a good place for such discussion to continue; closing.
I'm trying to use a constant at compile time to define the length of some vectors:
(code from glfw3-rs)
I get this error:
Is this a bug or by design?