Skip to content

Commit

Permalink
Fix #16; Coerce types for Object.Outer and Object.Class.
Browse files Browse the repository at this point in the history
  • Loading branch information
EliotVU committed Apr 22, 2024
1 parent 3c892b7 commit ae6c32f
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 12 deletions.
39 changes: 38 additions & 1 deletion server/src/UC/Symbols/CoreSymbols.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { toName } from 'UC/name';
import {
NAME_ARRAYPROPERTY,
NAME_BOOLPROPERTY,
Expand Down Expand Up @@ -36,6 +37,7 @@ import {
import {
DEFAULT_RANGE,
ModifierFlags,
StaticIntType,
StaticNameType,
StaticObjectType,
StaticRotatorType,
Expand All @@ -44,7 +46,8 @@ import {
UCPackage,
UCPropertySymbol,
UCScriptStructSymbol,
addHashedSymbol
addHashedSymbol,
getSymbolOuterHash
} from './';

export const CORE_PACKAGE = new UCPackage(NAME_CORE);
Expand All @@ -53,12 +56,46 @@ export const IntrinsicObject = new UCClassSymbol({ name: NAME_OBJECT, range: DEF
IntrinsicObject.modifiers |= ModifierFlags.Native | ModifierFlags.Abstract;
IntrinsicObject.outer = CORE_PACKAGE;

export const IntrinsicVectorHash = getSymbolOuterHash(NAME_VECTOR.hash, NAME_OBJECT.hash);
export const IntrinsicVector = new UCScriptStructSymbol({ name: NAME_VECTOR, range: DEFAULT_RANGE });
IntrinsicVector.modifiers |= ModifierFlags.Native;
IntrinsicVector.outer = IntrinsicObject;

const VectorXProperty = new UCPropertySymbol(
{ name: toName('X'), range: DEFAULT_RANGE },
DEFAULT_RANGE, StaticIntType);
IntrinsicVector.addSymbol(VectorXProperty);

const VectorYProperty = new UCPropertySymbol(
{ name: toName('Y'), range: DEFAULT_RANGE },
DEFAULT_RANGE, StaticIntType);
IntrinsicVector.addSymbol(VectorYProperty);

const VectorZProperty = new UCPropertySymbol(
{ name: toName('Z'), range: DEFAULT_RANGE },
DEFAULT_RANGE, StaticIntType);
IntrinsicVector.addSymbol(VectorZProperty);

export const IntrinsicRotatorHash = getSymbolOuterHash(NAME_ROTATOR.hash, NAME_OBJECT.hash);
export const IntrinsicRotator = new UCScriptStructSymbol({ name: NAME_ROTATOR, range: DEFAULT_RANGE });
IntrinsicRotator.modifiers |= ModifierFlags.Native;
IntrinsicRotator.outer = IntrinsicObject;

const RotatorPitchProperty = new UCPropertySymbol(
{ name: toName('Pitch'), range: DEFAULT_RANGE },
DEFAULT_RANGE, StaticIntType);
IntrinsicRotator.addSymbol(RotatorPitchProperty);

const RotatorYawProperty = new UCPropertySymbol(
{ name: toName('Yaw'), range: DEFAULT_RANGE },
DEFAULT_RANGE, StaticIntType);
IntrinsicRotator.addSymbol(RotatorYawProperty);

const RotatorRollProperty = new UCPropertySymbol(
{ name: toName('Roll'), range: DEFAULT_RANGE },
DEFAULT_RANGE, StaticIntType);
IntrinsicRotator.addSymbol(RotatorRollProperty);

export const Object_OuterProperty = new UCPropertySymbol(
{ name: NAME_OUTER, range: DEFAULT_RANGE },
DEFAULT_RANGE, StaticObjectType);
Expand Down
43 changes: 36 additions & 7 deletions server/src/UC/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
IWithInnerSymbols,
Identifier,
IntrinsicClass,
IntrinsicObject,
IntrinsicRngLiteral,
IntrinsicRotLiteral,
IntrinsicRotator,
Expand Down Expand Up @@ -48,15 +49,16 @@ import {
UCSymbolKind,
UCTypeKind,
UCTypeSymbol,
findOrIndexClassSymbol,
findOverloadedBinaryOperator,
findOverloadedPostOperator,
findOverloadedPreOperator,
findSuperStruct,
getContext,
getOuter,
getSymbolHash,
getSymbolOuterHash,
hasDefinedBaseType,
areIdentityMatch,
isArchetypeSymbol,
isConstSymbol,
isFunction,
Expand All @@ -66,11 +68,13 @@ import {
isStruct,
resolveType,
tryFindClassSymbol,
IntrinsicVectorHash,
IntrinsicRotatorHash,
} from './Symbols';
import { UCDocument } from './document';
import { intersectsWith } from './helpers';
import { config, getConstSymbol, getEnumMember } from './indexer';
import { NAME_ROTATOR, NAME_STRUCT, NAME_VECTOR } from './names';
import { NAME_CLASS, NAME_OUTER, NAME_ROTATOR, NAME_STRUCT, NAME_VECTOR } from './names';
import { SymbolWalker } from './symbolWalker';

export interface IExpression extends INode, IWithIndex, IWithInnerSymbols {
Expand Down Expand Up @@ -240,9 +244,9 @@ export class UCCallExpression extends UCExpression {
const returnValue = symbol.returnValue;
if (returnValue) {
// Coerce the return type to match that of the first passed argument, e.g. "coerce Object Spawn(class'Actor' actor);"
if (returnValue.hasAnyModifierFlags(ModifierFlags.Coerce) && this.arguments) {
const firstArgumentType = this.arguments[0]?.getType();
return firstArgumentType;
if (returnValue.hasAnyModifierFlags(ModifierFlags.Coerce) && this.arguments && this.arguments.length > 0) {
const firstArgumentType = this.arguments[0].getType();
return firstArgumentType && resolveType(firstArgumentType);
}

const returnValueType = returnValue.getType();
Expand Down Expand Up @@ -294,11 +298,15 @@ export class UCCallExpression extends UCExpression {
this.expression.type = type;
} else if (name === NAME_VECTOR) {
type = new UCObjectTypeSymbol(this.expression.id);
(type as UCObjectTypeSymbol).setRef(IntrinsicVector, document);
// Try work with the declared native struct instead of the intrinsic struct. (so that Vector(MyVec).X will resolve properly, as well as go to definition)
// Fall back to the intrinsic struct for situations where we have no Object.uc in the workspace.
const nativeStruct = OuterObjectsTable.getSymbol(IntrinsicVectorHash, UCSymbolKind.ScriptStruct) ?? IntrinsicVector;
(type as UCObjectTypeSymbol).setRef(nativeStruct, document);
this.expression.type = type;
} else if (name === NAME_ROTATOR) {
type = new UCObjectTypeSymbol(this.expression.id);
(type as UCObjectTypeSymbol).setRef(IntrinsicRotator, document);
const nativeStruct = OuterObjectsTable.getSymbol(IntrinsicRotatorHash, UCSymbolKind.ScriptStruct) ?? IntrinsicRotator;
(type as UCObjectTypeSymbol).setRef(nativeStruct, document);
this.expression.type = type;
} else if (name === NAME_STRUCT) {
type = new UCObjectTypeSymbol(this.expression.id);
Expand Down Expand Up @@ -637,16 +645,25 @@ export class UCAssignmentOperatorExpression extends UCBinaryOperatorExpression {

export class UCMemberExpression extends UCExpression {
public type?: ITypeSymbol;
private coercedType?: ITypeSymbol;

constructor(readonly id: Identifier) {
super(id.range);
}

override getMemberSymbol() {
if (this.coercedType) {
return this.coercedType.getRef();
}

return this.type?.getRef();
}

override getType() {
if (this.coercedType) {
return this.coercedType;
}

const symbol = this.type?.getRef();
// We resolve UCMethodSymbols in UCCallExpression, because we don't want to return the function's type in assignment expressions...
if (symbol) {
Expand All @@ -662,6 +679,10 @@ export class UCMemberExpression extends UCExpression {
}

getContainedSymbolAtPos(_position: Position) {
if (this.coercedType) {
return this.coercedType;
}

// Only return if we have a RESOLVED reference.
return this.type?.getRef() && this.type;
}
Expand Down Expand Up @@ -697,6 +718,14 @@ export class UCMemberExpression extends UCExpression {
} else {
member = getEnumMember(id);
}
} else if (member.getName() === NAME_CLASS && areIdentityMatch(member.outer, IntrinsicObject)) {
const classContext = getContext<UCClassSymbol>(context, UCSymbolKind.Class)!;
const coercedType = new UCObjectTypeSymbol(this.id);
coercedType.setRefNoIndex(classContext);
this.coercedType = coercedType;
} else if (member.getName() === NAME_OUTER && areIdentityMatch(member.outer, IntrinsicObject)) {
const classContext = getContext<UCClassSymbol>(context, UCSymbolKind.Class)!;
this.coercedType = classContext.withinType;
}

if (member) {
Expand Down
6 changes: 3 additions & 3 deletions server/src/UC/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
UCClassSymbol,
UCObjectSymbol,
UCSymbolKind,
getContext,
getOuter,
hasModifiers,
isField,
Expand Down Expand Up @@ -252,10 +253,9 @@ export function getSymbol(uri: DocumentUri, position: Position): ISymbol | undef
}

export function getSymbolDocument(symbol: ISymbol): UCDocument | undefined {
const documentClass = symbol && (symbol.kind === UCSymbolKind.Class
? (symbol as UCClassSymbol)
: getOuter<UCClassSymbol>(symbol, UCSymbolKind.Class));
console.assert(typeof symbol !== 'undefined');

const documentClass = getContext<UCClassSymbol>(symbol, UCSymbolKind.Class);
const document = documentClass && getDocumentById(documentClass.id.name);
return document;
}
Expand Down
3 changes: 2 additions & 1 deletion server/src/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
UCStructSymbol,
UCSymbolKind,
UCTypeKind,
areIdentityMatch,
areMethodsCompatibleWith,
findOrIndexClassSymbol,
getDebugSymbolInfo,
Expand Down Expand Up @@ -212,7 +213,7 @@ function getCallableMethods(document: UCDocument, contextSymbol: UCStructSymbol)
.getCompletionSymbols<UCMethodSymbol>(document, ContextKind.None, MethodSymbolKinds)
.filter(method => {
return method.super == null
&& ((method.modifiers & ModifierFlags.Private) == 0 || (method.getHash() == contextSymbol.getHash()));
&& ((method.modifiers & ModifierFlags.Private) == 0 || (areIdentityMatch(method, contextSymbol)));
});
}

Expand Down

0 comments on commit ae6c32f

Please sign in to comment.