Skip to content

Commit

Permalink
Implement params[] typehints
Browse files Browse the repository at this point in the history
  • Loading branch information
out-of-phaze committed Oct 31, 2024
1 parent cbb600f commit dfb49e9
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 92 deletions.
218 changes: 138 additions & 80 deletions DMCompiler/Compiler/DM/DMParser.cs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion DMCompiler/DM/Builders/DMExpressionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ private static DMExpression BuildDereference(DMASTDereference deref, DMObject dm
return BadExpression(WarningCode.ItemDoesntExist, callOperation.Location,
$"Type {prevPath.Value} does not have a proc named \"{field}\"");

var returnTypes = fromObject.GetProcReturnTypes(field) ?? DMValueType.Anything;
var returnTypes = fromObject.GetProcReturnTypes(field, argumentList) ?? DMValueType.Anything;
nextPath = returnTypes.HasPath ? returnTypes.TypePath : returnTypes.AsPath();
if (!returnTypes.HasPath & nextPath.HasValue) {
var thePath = nextPath!.Value;
Expand Down
15 changes: 10 additions & 5 deletions DMCompiler/DM/DMObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using DMCompiler.Bytecode;
using DMCompiler.Bytecode;
using DMCompiler.Compiler;
using DMCompiler.Json;

Expand Down Expand Up @@ -95,16 +95,21 @@ public bool HasProcNoInheritance(string name) {
}

public DMComplexValueType? GetProcReturnTypes(string name) {

return GetProcReturnTypes(name, null);

Check warning

Code scanning / InspectCode

Incorrect blank lines: Incorrect number of blank lines near braces Warning

Incorrect number of blank lines near braces, expected maximum 0 instead of 1
}

public DMComplexValueType? GetProcReturnTypes(string name, ArgumentList? arguments) {
if (this == DMObjectTree.Root && DMObjectTree.TryGetGlobalProc(name, out var globalProc))
return globalProc.RawReturnTypes;
return globalProc.GetParameterValueTypes(arguments);
if (GetProcs(name) is not { } procs)
return Parent?.GetProcReturnTypes(name);
return Parent?.GetProcReturnTypes(name, arguments);

var proc = DMObjectTree.AllProcs[procs[0]];
if ((proc.Attributes & ProcAttributes.IsOverride) != 0)
return Parent?.GetProcReturnTypes(name) ?? DMValueType.Anything;
return Parent?.GetProcReturnTypes(name, arguments) ?? DMValueType.Anything;

return proc.RawReturnTypes;
return proc.GetParameterValueTypes(arguments);
}

public void AddVerb(DMProc verb) {
Expand Down
46 changes: 46 additions & 0 deletions DMCompiler/DM/DMProc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,52 @@ public DMReference GetLocalVariableReference(string name) {
return local.IsParameter ? DMReference.CreateArgument(local.Id) : DMReference.CreateLocal(local.Id);
}

public DMProc GetBaseProc(DMObject? dmObject = null) {
if (dmObject == null) dmObject = _dmObject;

Check notice

Code scanning / InspectCode

'if' statement can be rewritten as '??=' assignment Note

Convert into '??='
if (dmObject == DMObjectTree.Root && DMObjectTree.TryGetGlobalProc(Name, out var globalProc))
return globalProc;
if (dmObject.GetProcs(Name) is not { } procs)
return dmObject.Parent is not null ? GetBaseProc(dmObject.Parent) : this;

var proc = DMObjectTree.AllProcs[procs[0]];
if ((proc.Attributes & ProcAttributes.IsOverride) != 0)
return dmObject.Parent is not null ? GetBaseProc(dmObject.Parent) : this;

return proc;
}

public DMComplexValueType GetParameterValueTypes(ArgumentList? arguments) {
return GetParameterValueTypes(RawReturnTypes, arguments);
}

public DMComplexValueType GetParameterValueTypes(DMComplexValueType? baseType, ArgumentList? arguments) {
if (baseType?.ParameterIndices is null) {
return baseType ?? DMValueType.Anything;
}
DMComplexValueType returnType = baseType ?? DMValueType.Anything;

Check warning

Code scanning / InspectCode

Incorrect blank lines: Blank lines are missing elsewhere Warning

Blank lines are missing, expected minimum 1 instead of 0

Check warning

Code scanning / InspectCode

'??' condition is known to be null or not null Warning

'??' left operand is never null
foreach ((int parameterIndex, bool upcasted) in baseType!.Value.ParameterIndices) {
DMComplexValueType intermediateType = DMValueType.Anything;
if (arguments is null || parameterIndex >= arguments.Expressions.Length) {
if (!TryGetParameterAtIndex(parameterIndex, out var parameter)) {
DMCompiler.Emit(WarningCode.BadArgument, Location, $"Unable to find argument with index {parameterIndex}");
continue;
}
intermediateType = parameter.ExplicitValueType ?? DMValueType.Anything;

Check warning

Code scanning / InspectCode

Incorrect blank lines: Blank lines are missing elsewhere Warning

Blank lines are missing, expected minimum 1 instead of 0
} else if (arguments is not null) {

Check warning

Code scanning / InspectCode

Expression is always 'true' or always 'false' Warning

Expression is always true
intermediateType = arguments.Expressions[parameterIndex].Expr.ValType;
}
if (upcasted) {

Check warning

Code scanning / InspectCode

Incorrect blank lines: Blank lines are missing elsewhere Warning

Blank lines are missing, expected minimum 1 instead of 0
if (!intermediateType.HasPath || (intermediateType.Type & ~(DMValueType.Path|DMValueType.Null)) != DMValueType.Anything) {
DMCompiler.Emit(WarningCode.InvalidVarType, arguments?.Location ?? Location, "Expected an exclusively path (or null) typed parameter");
} else {
intermediateType = new DMComplexValueType(intermediateType.Type & ~DMValueType.Path | DMValueType.Instance, intermediateType.TypePath);
}
}
returnType |= intermediateType;

Check warning

Code scanning / InspectCode

Incorrect blank lines: Blank lines are missing elsewhere Warning

Blank lines are missing, expected minimum 1 instead of 0
}

Check notice

Code scanning / InspectCode

Incorrect indent: Around statement braces Note

Line indent is not restored to the previous level around statement braces
return returnType;

Check warning

Code scanning / InspectCode

Incorrect blank lines: Blank lines are missing elsewhere Warning

Blank lines are missing, expected minimum 1 instead of 0
}

public void Error() {
WriteOpcode(DreamProcOpcode.Error);
}
Expand Down
17 changes: 15 additions & 2 deletions DMCompiler/DM/DMValueType.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace DMCompiler.DM;
namespace DMCompiler.DM;

// If you are modifying this, you must also modify OpenDreamShared.Dream.DreamValueType !!
// Unfortunately the client needs this and it can't reference DMCompiler due to the sandbox
Expand Down Expand Up @@ -37,6 +37,12 @@ public enum DMValueType {
public readonly struct DMComplexValueType {
public readonly DMValueType Type;
public readonly DreamPath? TypePath;
/// <summary>

Check warning

Code scanning / InspectCode

Incorrect blank lines: Blank lines are missing elsewhere Warning

Blank lines are missing, expected minimum 1 instead of 0
/// The indices of the proc parameters used to infer proc return types.
/// The resulting type is the union of all the parameter types with `this.Type`.
/// If two or more of those types have paths, their common ancestor is used.
/// </summary>
public readonly (int, bool)[]? ParameterIndices;

public bool IsAnything => Type == DMValueType.Anything;
public bool IsInstance => Type.HasFlag(DMValueType.Instance);
Expand All @@ -61,9 +67,16 @@ public DMComplexValueType(DMValueType type, DreamPath? typePath) {
throw new Exception("A Path or Instance value type must have a type-path");
}

public DMComplexValueType(DMValueType type, DreamPath? typePath, DMListValueTypes? listValueTypes) : this(type, typePath) {
public DMComplexValueType(DMValueType type, DreamPath? typePath, (int, bool)[]? parameterIndices) : this(type, typePath) {
ParameterIndices = parameterIndices;
}

public DMComplexValueType(DMValueType type, DreamPath? typePath, (int, bool)[]? parameterIndices, DMListValueTypes? listValueTypes) : this(type, typePath, parameterIndices) {
ListValueTypes = listValueTypes;
}

public DMComplexValueType(DMValueType type, DreamPath? typePath, DMListValueTypes? listValueTypes) : this(type, typePath, null, listValueTypes) { }

public bool MatchesType(DMValueType type) {
return IsAnything || (Type & type) != 0;
}
Expand Down
2 changes: 1 addition & 1 deletion DMCompiler/DM/Expressions/Dereference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private DMComplexValueType DetermineValType() {
type = operation switch {
FieldOperation fieldOperation => dmObject.GetVariable(fieldOperation.Identifier)?.ValType ?? DMValueType.Anything,
IndexOperation indexOperation => type.ListValueTypes is null ? DMValueType.Anything : (indexOperation.Index.ValType.Type.HasFlag(DMValueType.Num) ? type.ListValueTypes.NestedListKeyType : type.ListValueTypes.NestedListValType ?? type.ListValueTypes.NestedListKeyType) | DMValueType.Null, // TODO: Keys of assoc lists
CallOperation callOperation => dmObject.GetProcReturnTypes(callOperation.Identifier) ?? DMValueType.Anything,
CallOperation callOperation => dmObject.GetProcReturnTypes(callOperation.Identifier, callOperation.Parameters) ?? DMValueType.Anything,
_ => throw new InvalidOperationException("Unimplemented dereference operation")
};
}
Expand Down
6 changes: 3 additions & 3 deletions DMCompiler/DM/Expressions/Procs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public DMProc GetProc() {
/// This is an LValue _and_ a proc!
/// </summary>
internal sealed class ProcSelf(Location location, DreamPath? path, DMProc proc) : LValue(location, path) {
public override DMComplexValueType ValType => proc.RawReturnTypes;
public override DMComplexValueType ValType => proc.GetParameterValueTypes(null);

public override DMReference EmitReference(DMObject dmObject, DMProc proc, string endLabel, ShortCircuitMode shortCircuitMode = ShortCircuitMode.KeepNull) {
return DMReference.Self;
Expand Down Expand Up @@ -110,10 +110,10 @@ public override DMComplexValueType ValType {
return valType;
switch (target) {
case Proc procTarget:
return procTarget.dmObject.GetProcReturnTypes(procTarget.Identifier) ?? DMValueType.Anything;
return procTarget.dmObject.GetProcReturnTypes(procTarget.Identifier, arguments) ?? DMValueType.Anything;
case GlobalProc procTarget:
if(DMObjectTree.TryGetGlobalProc(procTarget.Identifier, out var globalProc))
return globalProc.RawReturnTypes ?? DMValueType.Anything;
return globalProc.GetParameterValueTypes(arguments);
return DMValueType.Anything;
}
return target.ValType;

Check warning

Code scanning / InspectCode

Incorrect blank lines: Blank lines are missing elsewhere Warning

Blank lines are missing, expected minimum 1 instead of 0
Expand Down

0 comments on commit dfb49e9

Please sign in to comment.