lang: ast, interfaces: Improve speculation safety checks
We want to speculate in more cases, so make sure that speculation is safe!
This commit is contained in:
@@ -10484,6 +10484,13 @@ func (obj *ExprVar) SetType(typ *types.Type) error {
|
|||||||
func (obj *ExprVar) Type() (*types.Type, error) {
|
func (obj *ExprVar) Type() (*types.Type, error) {
|
||||||
// TODO: should this look more like Type() in ExprCall or vice-versa?
|
// TODO: should this look more like Type() in ExprCall or vice-versa?
|
||||||
|
|
||||||
|
if obj.scope == nil { // avoid a possible nil panic if we speculate here
|
||||||
|
if obj.typ == nil {
|
||||||
|
return nil, errwrap.Wrapf(interfaces.ErrTypeCurrentlyUnknown, obj.String())
|
||||||
|
}
|
||||||
|
return obj.typ, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Return the type if it is already known statically... It is useful for
|
// Return the type if it is already known statically... It is useful for
|
||||||
// type unification to have some extra info early.
|
// type unification to have some extra info early.
|
||||||
expr, exists := obj.scope.Variables[obj.Name]
|
expr, exists := obj.scope.Variables[obj.Name]
|
||||||
@@ -10602,6 +10609,10 @@ func (obj *ExprVar) SetValue(value types.Value) error {
|
|||||||
// it can lookup in the previous set scope which expression this points to, and
|
// it can lookup in the previous set scope which expression this points to, and
|
||||||
// then it can call Value on that expression.
|
// then it can call Value on that expression.
|
||||||
func (obj *ExprVar) Value() (types.Value, error) {
|
func (obj *ExprVar) Value() (types.Value, error) {
|
||||||
|
if obj.scope == nil { // avoid a possible nil panic if we speculate here
|
||||||
|
return nil, errwrap.Wrapf(interfaces.ErrValueCurrentlyUnknown, obj.String())
|
||||||
|
}
|
||||||
|
|
||||||
expr, exists := obj.scope.Variables[obj.Name]
|
expr, exists := obj.scope.Variables[obj.Name]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, fmt.Errorf("var `%s` does not exist in scope", obj.Name)
|
return nil, fmt.Errorf("var `%s` does not exist in scope", obj.Name)
|
||||||
|
|||||||
@@ -36,8 +36,16 @@ import (
|
|||||||
const (
|
const (
|
||||||
// ErrTypeCurrentlyUnknown is returned from the Type() call on Expr if
|
// ErrTypeCurrentlyUnknown is returned from the Type() call on Expr if
|
||||||
// unification didn't run successfully and the type isn't obvious yet.
|
// unification didn't run successfully and the type isn't obvious yet.
|
||||||
|
// Note that it is perfectly legal to return any error, but this one can
|
||||||
|
// be used instead of inventing your own.
|
||||||
ErrTypeCurrentlyUnknown = util.Error("type is currently unknown")
|
ErrTypeCurrentlyUnknown = util.Error("type is currently unknown")
|
||||||
|
|
||||||
|
// ErrValueCurrentlyUnknown is returned from the Value() call on Expr if
|
||||||
|
// we're speculating and we don't know a value statically. Note that it
|
||||||
|
// is perfectly legal to return any error, but this one can be used
|
||||||
|
// instead of inventing your own.
|
||||||
|
ErrValueCurrentlyUnknown = util.Error("value is currently unknown")
|
||||||
|
|
||||||
// ErrExpectedFileMissing is returned when a file that is used by an
|
// ErrExpectedFileMissing is returned when a file that is used by an
|
||||||
// import is missing. This might signal the downloader, or it might
|
// import is missing. This might signal the downloader, or it might
|
||||||
// signal a permanent error.
|
// signal a permanent error.
|
||||||
|
|||||||
Reference in New Issue
Block a user