diff --git a/Sources/AST/AST.swift b/Sources/AST/AST.swift index 054d9b4b..9a4c82a0 100644 --- a/Sources/AST/AST.swift +++ b/Sources/AST/AST.swift @@ -158,7 +158,7 @@ public struct FunctionDeclaration: SourceEntity { /// The raw type of the function's return type. public var rawType: Type.RawType { - return resultType?.rawType ?? .builtInType(.void) + return resultType?.rawType ?? .basicType(.void) } public var sourceLocation: SourceLocation { @@ -307,7 +307,7 @@ public struct Parameter: SourceEntity { /// Whether the parameter is both `implicit` and has a currency type. public var isPayableValueParameter: Bool { - if isImplicit, case .builtInType(let type) = type.rawType, type.isCurrencyType { + if isImplicit, case .basicType(let type) = type.rawType, type.isCurrencyType { return true } return false @@ -367,7 +367,7 @@ public struct Identifier: Hashable, SourceEntity { public struct Type: SourceEntity { /// A Flint raw type, without a source location. public indirect enum RawType: Equatable { - case builtInType(BuiltInType) + case basicType(BasicType) case arrayType(RawType) case fixedSizeArrayType(RawType, size: Int) case dictionaryType(key: RawType, value: RawType) @@ -380,7 +380,7 @@ public struct Type: SourceEntity { switch self { case .fixedSizeArrayType(let rawType, size: let size): return "\(rawType.name)[\(size)]" case .arrayType(let rawType): return "[\(rawType.name)]" - case .builtInType(let builtInType): return "\(builtInType.rawValue)" + case .basicType(let builtInType): return "\(builtInType.rawValue)" case .dictionaryType(let keyType, let valueType): return "[\(keyType.name): \(valueType.name)]" case .userDefinedType(let identifier): return identifier case .inoutType(let rawType): return "&\(rawType)" @@ -389,18 +389,24 @@ public struct Type: SourceEntity { } } - public var isBasicType: Bool { - if case .builtInType(_) = self { return true } - return false + public var isBuiltInType: Bool { + switch self { + case .basicType(_), .any, .errorType: return true + case .arrayType(let element): return element.isBuiltInType + case .fixedSizeArrayType(let element, _): return element.isBuiltInType + case .dictionaryType(let key, let value): return key.isBuiltInType && value.isBuiltInType + case .inoutType(let element): return element.isBuiltInType + case .userDefinedType(_): return false + } } public var isEventType: Bool { - return self == .builtInType(.event) + return self == .basicType(.event) } /// Whether the type is a dynamic type. public var isDynamicType: Bool { - if case .builtInType(_) = self { + if case .basicType(_) = self { return false } @@ -427,7 +433,7 @@ public struct Type: SourceEntity { } } - public enum BuiltInType: String { + public enum BasicType: String { case address = "Address" case int = "Int" case string = "String" @@ -463,8 +469,8 @@ public struct Type: SourceEntity { public init(identifier: Identifier, genericArguments: [Type] = []) { let name = identifier.name - if let builtInType = BuiltInType(rawValue: name) { - rawType = .builtInType(builtInType) + if let builtInType = BasicType(rawValue: name) { + rawType = .basicType(builtInType) } else { rawType = .userDefinedType(name) } diff --git a/Sources/AST/ASTDumper.swift b/Sources/AST/ASTDumper.swift index 87832046..83ae6395 100644 --- a/Sources/AST/ASTDumper.swift +++ b/Sources/AST/ASTDumper.swift @@ -231,7 +231,7 @@ public class ASTDumper { self.dump(keyType) self.dump(valueType) } - case .builtInType(let builtInType): + case .basicType(let builtInType): writeNode("BuiltInType") { self.dump(builtInType) } @@ -248,7 +248,7 @@ public class ASTDumper { } } - func dump(_ builtInType: Type.BuiltInType) { + func dump(_ builtInType: Type.BasicType) { writeLine("built-in type \(builtInType.rawValue)") } diff --git a/Sources/AST/ASTPassContext.swift b/Sources/AST/ASTPassContext.swift index b7180709..fbad974d 100644 --- a/Sources/AST/ASTPassContext.swift +++ b/Sources/AST/ASTPassContext.swift @@ -55,6 +55,12 @@ extension ASTPassContext { set { self[AsLValueContextEntry.self] = newValue } } + /// Contextual information used when visiting the state properties declared in a contract declaration. + public var contractStateDeclarationContext: ContractStateDeclarationContext? { + get { return self[ContractStateDeclarationContextEntry.self] } + set { self[ContractStateDeclarationContextEntry.self] = newValue } + } + /// Contextual information used when visiting functions in a contract behavior declaration, such as the name of the /// contract the functions are declared for, and the caller capability associated with them. public var contractBehaviorDeclarationContext: ContractBehaviorDeclarationContext? { @@ -114,6 +120,10 @@ private struct AsLValueContextEntry: PassContextEntry { typealias Value = Bool } +private struct ContractStateDeclarationContextEntry: PassContextEntry { + typealias Value = ContractStateDeclarationContext +} + private struct ContractBehaviorDeclarationContextEntry: PassContextEntry { typealias Value = ContractBehaviorDeclarationContext } diff --git a/Sources/AST/ASTVisitor.swift b/Sources/AST/ASTVisitor.swift index d3508e5b..176f5bec 100644 --- a/Sources/AST/ASTVisitor.swift +++ b/Sources/AST/ASTVisitor.swift @@ -57,10 +57,14 @@ public struct ASTVisitor { processResult.element.identifier = processResult.combining(visit(processResult.element.identifier, passContext: processResult.passContext)) + processResult.passContext.contractStateDeclarationContext = ContractStateDeclarationContext(contractIdentifier: contractDeclaration.identifier) + processResult.element.variableDeclarations = processResult.element.variableDeclarations.map { variableDeclaration in return processResult.combining(visit(variableDeclaration, passContext: processResult.passContext)) } + processResult.passContext.contractStateDeclarationContext = nil + let postProcessResult = pass.postProcess(contractDeclaration: processResult.element, passContext: processResult.passContext) return ASTPassResult(element: postProcessResult.element, diagnostics: processResult.diagnostics + postProcessResult.diagnostics, passContext: postProcessResult.passContext) } @@ -70,7 +74,7 @@ public struct ASTVisitor { var localVariables = [VariableDeclaration]() if let capabilityBinding = contractBehaviorDeclaration.capabilityBinding { - localVariables.append(VariableDeclaration(declarationToken: nil, identifier: capabilityBinding, type: Type(inferredType: .builtInType(.address), identifier: capabilityBinding))) + localVariables.append(VariableDeclaration(declarationToken: nil, identifier: capabilityBinding, type: Type(inferredType: .basicType(.address), identifier: capabilityBinding))) } let scopeContext = ScopeContext(localVariables: localVariables) diff --git a/Sources/AST/ASTVisitorContext.swift b/Sources/AST/ASTVisitorContext.swift index f48008f4..4e4a183a 100644 --- a/Sources/AST/ASTVisitorContext.swift +++ b/Sources/AST/ASTVisitorContext.swift @@ -5,6 +5,11 @@ // Created by Franklin Schrans on 1/11/18. // +/// Contextual information used when visiting the state properties declared in a contract declaration. +public struct ContractStateDeclarationContext { + public var contractIdentifier: Identifier +} + /// Contextual information used when visiting functions in a contract behavior declaration, such as the name of the /// contract the functions are declared for, and the caller capability associated with them. public struct ContractBehaviorDeclarationContext { diff --git a/Sources/AST/Environment.swift b/Sources/AST/Environment.swift index fd69abd1..a4e1ea87 100644 --- a/Sources/AST/Environment.swift +++ b/Sources/AST/Environment.swift @@ -116,9 +116,9 @@ public struct Environment { func declaredCallerCapabilities(enclosingType: RawTypeIdentifier) -> [String] { return types[enclosingType]!.properties.compactMap { key, value in switch value.rawType { - case .builtInType(.address): return key - case .fixedSizeArrayType(.builtInType(.address), _): return key - case .arrayType(.builtInType(.address)): return key + case .basicType(.address): return key + case .fixedSizeArrayType(.basicType(.address), _): return key + case .arrayType(.basicType(.address)): return key default: return nil } } @@ -145,13 +145,13 @@ public struct Environment { return matchingFunction.resultType } - /// The type of a literal token. + /// The types a literal token can be. public func type(ofLiteralToken literalToken: Token) -> Type.RawType { guard case .literal(let literal) = literalToken.kind else { fatalError() } switch literal { - case .boolean(_): return .builtInType(.bool) - case .decimal(.integer(_)): return .builtInType(.int) - case .string(_): return .builtInType(.string) + case .boolean(_): return .basicType(.bool) + case .decimal(.integer(_)): return .basicType(.int) + case .string(_): return .basicType(.string) default: fatalError() } } @@ -223,7 +223,7 @@ public struct Environment { return .inoutType(type(of: inoutExpression.expression, enclosingType: enclosingType, callerCapabilities: callerCapabilities, scopeContext: scopeContext)) case .binaryExpression(let binaryExpression): if binaryExpression.opToken.isBooleanOperator { - return .builtInType(.bool) + return .basicType(.bool) } return type(of: binaryExpression.rhs, enclosingType: enclosingType, callerCapabilities: callerCapabilities, scopeContext: scopeContext) @@ -333,8 +333,8 @@ public struct Environment { /// The memory size of a type, in terms of number of memory slots it occupies. public func size(of type: Type.RawType) -> Int { switch type { - case .builtInType(.event): return 0 // Events do not use memory. - case .builtInType(_): return 1 + case .basicType(.event): return 0 // Events do not use memory. + case .basicType(_): return 1 case .fixedSizeArrayType(let rawType, let elementCount): return size(of: rawType) * elementCount case .arrayType(_): return 1 case .dictionaryType(_, _): return 1 diff --git a/Sources/IRGen/Function/IULIAFunction.swift b/Sources/IRGen/Function/IULIAFunction.swift index 6c9f0048..2ea6751c 100644 --- a/Sources/IRGen/Function/IULIAFunction.swift +++ b/Sources/IRGen/Function/IULIAFunction.swift @@ -52,7 +52,7 @@ struct IULIAFunction { var scopeContext: ScopeContext { var localVariables = functionDeclaration.parametersAsVariableDeclarations if let capabilityBinding = capabilityBinding { - localVariables.append(VariableDeclaration(declarationToken: nil, identifier: capabilityBinding, type: Type(inferredType: .builtInType(.address), identifier: capabilityBinding))) + localVariables.append(VariableDeclaration(declarationToken: nil, identifier: capabilityBinding, type: Type(inferredType: .basicType(.address), identifier: capabilityBinding))) } return ScopeContext(localVariables: localVariables) } @@ -103,7 +103,7 @@ struct IULIAFunctionBody { var scopeContext: ScopeContext { var localVariables = functionDeclaration.parametersAsVariableDeclarations if let capabilityBinding = capabilityBinding { - localVariables.append(VariableDeclaration(declarationToken: nil, identifier: capabilityBinding, type: Type(inferredType: .builtInType(.address), identifier: capabilityBinding))) + localVariables.append(VariableDeclaration(declarationToken: nil, identifier: capabilityBinding, type: Type(inferredType: .basicType(.address), identifier: capabilityBinding))) } return ScopeContext(localVariables: localVariables) } diff --git a/Sources/IRGen/Function/IULIAInitializer.swift b/Sources/IRGen/Function/IULIAInitializer.swift index 5249634f..95d880eb 100644 --- a/Sources/IRGen/Function/IULIAInitializer.swift +++ b/Sources/IRGen/Function/IULIAInitializer.swift @@ -36,7 +36,7 @@ struct IULIAInitializer { var scopeContext: ScopeContext { var localVariables = initializerDeclaration.parametersAsVariableDeclarations if let capabilityBinding = capabilityBinding { - localVariables.append(VariableDeclaration(declarationToken: nil, identifier: capabilityBinding, type: Type(inferredType: .builtInType(.address), identifier: capabilityBinding))) + localVariables.append(VariableDeclaration(declarationToken: nil, identifier: capabilityBinding, type: Type(inferredType: .basicType(.address), identifier: capabilityBinding))) } return ScopeContext(localVariables: localVariables) } diff --git a/Sources/IRGen/IULIACanonicalType.swift b/Sources/IRGen/IULIACanonicalType.swift index cd2e66dc..88dc6075 100644 --- a/Sources/IRGen/IULIACanonicalType.swift +++ b/Sources/IRGen/IULIACanonicalType.swift @@ -15,7 +15,7 @@ enum CanonicalType: String { init?(from rawType: Type.RawType) { switch rawType { - case .builtInType(let builtInType): + case .basicType(let builtInType): switch builtInType { case .address: self = .address case .int, .bool, .wei: self = .uint256 diff --git a/Sources/Parser/Parser.swift b/Sources/Parser/Parser.swift index 1a2c8c1c..11091c04 100644 --- a/Sources/Parser/Parser.swift +++ b/Sources/Parser/Parser.swift @@ -411,7 +411,7 @@ extension Parser { let (callerCapabilities, closeBracketToken) = try parseCallerCapabilityGroup() try consume(.punctuation(.openBrace)) - let members = try parseContractBehaviorMembers() + let members = try parseContractBehaviorMembers(contractIdentifier: contractIdentifier.name) try consume(.punctuation(.closeBrace)) @@ -447,7 +447,7 @@ extension Parser { return callerCapabilities } - func parseContractBehaviorMembers() throws -> [ContractBehaviorMember] { + func parseContractBehaviorMembers(contractIdentifier: RawTypeIdentifier) throws -> [ContractBehaviorMember] { var members = [ContractBehaviorMember]() while true { @@ -455,6 +455,12 @@ extension Parser { members.append(.functionDeclaration(functionDeclaration)) } else if let initializerDeclaration = attempt(task: parseInitializerDeclaration) { members.append(.initializerDeclaration(initializerDeclaration)) + + if initializerDeclaration.isPublic, environment.publicInitializer(forContract: contractIdentifier) == nil { + // Record the public initializer, we will need to know if one of was declared during semantic analysis of the + // contract's state properties. + environment.setPublicInitializer(initializerDeclaration, forContract: contractIdentifier) + } } else { break } diff --git a/Sources/SemanticAnalyzer/SemanticAnalyzer.swift b/Sources/SemanticAnalyzer/SemanticAnalyzer.swift index e4c06ebe..0067dbd9 100644 --- a/Sources/SemanticAnalyzer/SemanticAnalyzer.swift +++ b/Sources/SemanticAnalyzer/SemanticAnalyzer.swift @@ -58,10 +58,12 @@ public struct SemanticAnalyzer: ASTPass { var passContext = passContext var diagnostics = [Diagnostic]() - if let _ = passContext.functionDeclarationContext { + let inFunctionOrInitializer = passContext.functionDeclarationContext != nil || passContext.initializerDeclarationContext != nil + + if inFunctionOrInitializer { // We're in a function. Record the local variable declaration. passContext.scopeContext?.localVariables += [variableDeclaration] - } else { + } else if let contractStateDeclarationContext = passContext.contractStateDeclarationContext { // This is a state property declaration. // If a default value is assigned, it should be a literal. @@ -76,6 +78,12 @@ public struct SemanticAnalyzer: ASTPass { if !assignedExpression.isLiteral { diagnostics.append(.statePropertyDeclarationIsAssignedANonLiteralExpression(variableDeclaration)) } + } else { + if variableDeclaration.type.rawType.isBuiltInType && !variableDeclaration.type.rawType.isEventType && passContext.environment!.publicInitializer(forContract: contractStateDeclarationContext.contractIdentifier.name) == nil { + // The contract has no public initializer, so a default value must be provided. + + diagnostics.append(.statePropertyIsNotAssignedAValue(variableDeclaration)) + } } } @@ -372,7 +380,8 @@ public struct SemanticAnalyzer: ASTPass { if !context.callerCapabilities.contains(where: { $0.isAny }) { diagnostics.append(.contractInitializerNotDeclaredInAnyCallerCapabilityBlock(initializerDeclaration)) } else { - if let publicInitializer = passContext.environment!.publicInitializer(forContract: contractName) { + if let publicInitializer = passContext.environment!.publicInitializer(forContract: contractName), publicInitializer.sourceLocation != initializerDeclaration.sourceLocation { + // There can be at most one public initializer. diagnostics.append(.multiplePublicInitializersDefined(initializerDeclaration, originalInitializerLocation: publicInitializer.sourceLocation)) } else { // This is the first public initializer we encounter in this contract. @@ -382,8 +391,13 @@ public struct SemanticAnalyzer: ASTPass { } // Check all the properties in the type have been assigned. - if let unassignedProperties = passContext.unassignedProperties, unassignedProperties.count > 0 { - diagnostics.append(.returnFromInitializerWithoutInitializingAllProperties(initializerDeclaration, unassignedProperties: unassignedProperties)) + if let unassignedProperties = passContext.unassignedProperties { + let propertiesWithBuiltInTypes = unassignedProperties.filter { $0.type.rawType.isBuiltInType && !$0.type.rawType.isEventType } + + // For now, only non user-defined types need to be assigned a value. + if propertiesWithBuiltInTypes.count > 0 { + diagnostics.append(.returnFromInitializerWithoutInitializingAllProperties(initializerDeclaration, unassignedProperties: unassignedProperties)) + } } return ASTPassResult(element: initializerDeclaration, diagnostics: diagnostics, passContext: passContext) diff --git a/Sources/SemanticAnalyzer/SemanticError.swift b/Sources/SemanticAnalyzer/SemanticError.swift index bc5b5efb..dbb006ce 100644 --- a/Sources/SemanticAnalyzer/SemanticError.swift +++ b/Sources/SemanticAnalyzer/SemanticError.swift @@ -56,8 +56,8 @@ extension Diagnostic { return Diagnostic(severity: .error, sourceLocation: variableDeclaration.sourceLocation, message: "The default value assigned to a state property must be a literal") } - static func constantStatePropertyIsNotAssignedAValue(_ variableDeclaration: VariableDeclaration) -> Diagnostic { - return Diagnostic(severity: .error, sourceLocation: variableDeclaration.sourceLocation, message: "'let' constant '\(variableDeclaration.identifier.name)' needs to be assigned a value") + static func statePropertyIsNotAssignedAValue(_ variableDeclaration: VariableDeclaration) -> Diagnostic { + return Diagnostic(severity: .error, sourceLocation: variableDeclaration.sourceLocation, message: "State property '\(variableDeclaration.identifier.name)' needs to be assigned a value") } static func returnFromInitializerWithoutInitializingAllProperties(_ initializerDeclaration: InitializerDeclaration, unassignedProperties: [VariableDeclaration]) -> Diagnostic { diff --git a/Sources/SemanticAnalyzer/TypeChecker.swift b/Sources/SemanticAnalyzer/TypeChecker.swift index 87b7c6a8..9a2204b5 100644 --- a/Sources/SemanticAnalyzer/TypeChecker.swift +++ b/Sources/SemanticAnalyzer/TypeChecker.swift @@ -67,7 +67,9 @@ public struct TypeChecker: ASTPass { rhsType = nil } - if let rhsType = rhsType, !lhsType.isCompatible(with: rhsType), ![lhsType, rhsType].contains(.errorType) { + // Numeric literals can be assigned to Wei properties (until we support struct initializers) + if let rhsType = rhsType, rhsType == .basicType(.int), lhsType == .basicType(.wei) { + } else if let rhsType = rhsType, !lhsType.isCompatible(with: rhsType), ![lhsType, rhsType].contains(.errorType) { diagnostics.append(.incompatibleAssignment(lhsType: lhsType, rhsType: rhsType, expression: assignedExpression)) } } diff --git a/Tests/BehaviorTests/tests/array/array.flint b/Tests/BehaviorTests/tests/array/array.flint index cf194acb..ecf5e8b6 100644 --- a/Tests/BehaviorTests/tests/array/array.flint +++ b/Tests/BehaviorTests/tests/array/array.flint @@ -1,9 +1,9 @@ contract Array { - var arr: Int[4] - var arr2: Int[10] - var numWrites: Int + var arr: Int[4] = [] + var arr2: Int[10] = [] + var numWrites: Int = 0 - var arr3: [S] + var arr3: [S] = [] } Array :: (any) { diff --git a/Tests/BehaviorTests/tests/bank/bank.flint b/Tests/BehaviorTests/tests/bank/bank.flint index f429bd90..9238a7f4 100644 --- a/Tests/BehaviorTests/tests/bank/bank.flint +++ b/Tests/BehaviorTests/tests/bank/bank.flint @@ -1,10 +1,10 @@ contract Bank { var manager: Address - var balances: [Address: Int] - var accounts: [Address] - var lastIndex: Int + var balances: [Address: Int] = [:] + var accounts: [Address] = [] + var lastIndex: Int = 0 - var totalDonations: Wei + var totalDonations: Wei = 0 } Bank :: account <- (any) { diff --git a/Tests/BehaviorTests/tests/dictionary/dictionary.flint b/Tests/BehaviorTests/tests/dictionary/dictionary.flint index 122dbdde..81f9781d 100644 --- a/Tests/BehaviorTests/tests/dictionary/dictionary.flint +++ b/Tests/BehaviorTests/tests/dictionary/dictionary.flint @@ -1,10 +1,10 @@ contract Dictionary { - var storage: [Address: Int] - var foo: Int - var storage2: [Address: Int] - var bar: Int + var storage: [Address: Int] = [:] + var foo: Int = 0 + var storage2: [Address: Int] = [:] + var bar: Int = 0 - var storage3: [Int: S] + var storage3: [Int: S] = [:] } struct S { diff --git a/Tests/BehaviorTests/tests/factorial/factorial.flint b/Tests/BehaviorTests/tests/factorial/factorial.flint index a6583f41..1aeeaaa1 100644 --- a/Tests/BehaviorTests/tests/factorial/factorial.flint +++ b/Tests/BehaviorTests/tests/factorial/factorial.flint @@ -1,5 +1,5 @@ contract Factorial { - var value: Int + var value: Int = 0 } Factorial :: (any) { diff --git a/Tests/ParserTests/array.flint b/Tests/ParserTests/array.flint index bfb61e57..d472b54a 100644 --- a/Tests/ParserTests/array.flint +++ b/Tests/ParserTests/array.flint @@ -29,15 +29,23 @@ contract Test { // CHECK-AST: VariableDeclaration // CHECK-AST: identifier "numWrites" // CHECK-AST: built-in type Int - var numWrites: Int +// CHECK-AST: 0 + var numWrites: Int = 0 } // CHECK-AST: TopLevelDeclaration // CHECK-AST: ContractBehaviorDeclaration // CHECK-AST: identifier "Test" +// CHECK-AST: capability binding "caller" // CHECK-AST: CallerCapability // CHECK-AST: identifier "any" -Test :: (any) { +Test :: caller <- (any) { + +// CHECK-AST: InitializerDeclaration +// CHECK-AST: public + public init() { + self.owner = caller + } // CHECK-AST: FunctionDeclaration // CHECK-AST: mutating diff --git a/Tests/ParserTests/branching.flint b/Tests/ParserTests/branching.flint index cfbf941e..f518fbe9 100644 --- a/Tests/ParserTests/branching.flint +++ b/Tests/ParserTests/branching.flint @@ -2,10 +2,14 @@ contract Wallet { var owner: Address - var contents: Int + var contents: Int = 0 } Wallet :: (any) { + public init(owner: Address) { + self.owner = owner + } + public func factorial(n: Int) -> Int { // CHECK-AST: IfStatement diff --git a/Tests/ParserTests/types.flint b/Tests/ParserTests/types.flint index fc395421..75b5fda3 100644 --- a/Tests/ParserTests/types.flint +++ b/Tests/ParserTests/types.flint @@ -8,7 +8,7 @@ contract Foo { // CHECK-AST: FixedSizeArrayType // CHECK-AST: built-in type Int // CHECK-AST: size 16 - var array: Int[16] + var array: Int[16] = [] // CHECK-AST: VariableDeclaration // CHECK-AST: identifier "dictionary" @@ -21,7 +21,7 @@ contract Foo { // CHECK-AST: VariableDeclaration // CHECK-AST: identifier "value" // CHECK-AST: built-in type Int - var value: Int + var value: Int = 0 // CHECK-AST: VariableDeclaration // CHECK-AST: identifier "didCompleteSomething" diff --git a/Tests/SemanticTests/constants.flint b/Tests/SemanticTests/constants.flint index 05b743e0..711f23ce 100644 --- a/Tests/SemanticTests/constants.flint +++ b/Tests/SemanticTests/constants.flint @@ -1,34 +1,34 @@ // RUN: %flintc %s --verify contract Constants { - var a: Int + var a: Int // expected-error {{State property 'a' needs to be assigned a value}} var b: Int = "a" // expected-error {{Incompatible assignment between values of type Int and String}} let c: Int = 2 + 3 // expected-error {{The default value assigned to a state property must be a literal}} let d: Int = 3 - let e: Int // expected-error {{'let' constant 'e' needs to be assigned a value}} + let e: Int // expected-error {{State property 'e' needs to be assigned a value}} } Constants :: (any) { mutating func foo() { let a: Int = 2 // expected-note {{'a' is declared here}} - a = 3 // expected-error {{Cannot assign to value: 'a' is a 'let' constant}} + a = 3 // expected-error {{Cannot reassign to value: 'a' is a 'let' constant}} let b: Int = a self.a = 3 if true { - a = 5 // expected-error {{Cannot assign to value: 'a' is a 'let' constant}} + a = 5 // expected-error {{Cannot reassign to value: 'a' is a 'let' constant}} } else { - a = 7 // expected-error {{Cannot assign to value: 'a' is a 'let' constant}} + a = 7 // expected-error {{Cannot reassign to value: 'a' is a 'let' constant}} } - d = 4 // expected-error {{Cannot assign to value: 'd' is a 'let' constant}} + d = 4 // expected-error {{Cannot reassign to value: 'd' is a 'let' constant}} } mutating func bar() { var d: Bool = true d = false - self.d = 5 // expected-error {{Cannot assign to value: 'd' is a 'let' constant}} + self.d = 5 // expected-error {{Cannot reassign to value: 'd' is a 'let' constant}} } } diff --git a/Tests/SemanticTests/inits.flint b/Tests/SemanticTests/inits.flint index f050d5e8..3bfeca34 100644 --- a/Tests/SemanticTests/inits.flint +++ b/Tests/SemanticTests/inits.flint @@ -17,10 +17,12 @@ Test :: caller <- (any) { } init() { + self.a = caller } } Test :: (a) { public init(a: Address) { // expected-error {{Public contract initializer should be callable using caller capability "any"}} + self.a = a } } diff --git a/Tests/SemanticTests/invalid_function_call.flint b/Tests/SemanticTests/invalid_function_call.flint index eda75334..fa934f86 100644 --- a/Tests/SemanticTests/invalid_function_call.flint +++ b/Tests/SemanticTests/invalid_function_call.flint @@ -4,10 +4,14 @@ contract Test { var owner: Address } -Test :: (any) { +Test :: caller <- (any) { + public init() { + self.owner = caller + } + public func foo() { -// expected-error@11 {{Function bar is not in scope or cannot be called using the caller capabilities (any)}} +// expected-error@15 {{Function bar is not in scope or cannot be called using the caller capabilities (any)}} bar() } } diff --git a/Tests/SemanticTests/invalid_types.flint b/Tests/SemanticTests/invalid_types.flint index 1ec13f2f..916ef67b 100644 --- a/Tests/SemanticTests/invalid_types.flint +++ b/Tests/SemanticTests/invalid_types.flint @@ -1,8 +1,8 @@ // RUN: %flintc %s --verify contract InvalidTypes { - var int: Int - var a: Int + var int: Int = 0 + var a: Int = 0 } InvalidTypes :: (any) { diff --git a/Tests/SemanticTests/mutating.flint b/Tests/SemanticTests/mutating.flint index 20196bb0..3b21099c 100644 --- a/Tests/SemanticTests/mutating.flint +++ b/Tests/SemanticTests/mutating.flint @@ -1,8 +1,8 @@ // RUN: %flintc %s --verify contract Test { - var a: Int[10] - var b: Int + var a: Int[10] = [] + var b: Int = 0 var f: Foo } diff --git a/Tests/SemanticTests/structs.flint b/Tests/SemanticTests/structs.flint index c1c990dc..db6d0cf9 100644 --- a/Tests/SemanticTests/structs.flint +++ b/Tests/SemanticTests/structs.flint @@ -13,7 +13,7 @@ struct Test2 { } contract Foo { - var c: Int + var c: Int = 0 var a: Test var b: Test2 } diff --git a/Tests/SemanticTests/undeclared_capability.flint b/Tests/SemanticTests/undeclared_capability.flint index 2c68e13b..993ff69a 100644 --- a/Tests/SemanticTests/undeclared_capability.flint +++ b/Tests/SemanticTests/undeclared_capability.flint @@ -4,6 +4,12 @@ contract Test { var owner: Address } +Test :: caller <- (any) { + public init() { + self.owner = owner + } +} + Test :: (alice) { // expected-error {{Caller capability alice is undefined in Test or has incompatible type}} func bar() { } diff --git a/Tests/SemanticTests/use_undeclared_identifier.flint b/Tests/SemanticTests/use_undeclared_identifier.flint index 7ff7a3c2..d25a57ae 100644 --- a/Tests/SemanticTests/use_undeclared_identifier.flint +++ b/Tests/SemanticTests/use_undeclared_identifier.flint @@ -1,7 +1,7 @@ // RUN: %flintc %s --verify contract Test { - var x: Int + var x: Int = 0 } Test :: (any) {