Skip to content

Commit

Permalink
Merge pull request #1087 from hylo-lang/typecheck-for-stmt
Browse files Browse the repository at this point in the history
Type check for loops
  • Loading branch information
kyouko-taiga authored Oct 15, 2023
2 parents abfae82 + 49fc8fd commit ad2a3c6
Show file tree
Hide file tree
Showing 15 changed files with 483 additions and 108 deletions.
25 changes: 16 additions & 9 deletions Library/Hylo/Core/Bool.hylo
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,30 @@ public type Bool {
Bool(value: Builtin.or_i1(self.value, rhs.value))
}

/// Returns `true` if `self` is equal to `other`. Otherwise, returns `false`.
public fun infix== (_ other: Self) -> Bool {
Bool(value: Builtin.icmp_eq_i1(value, other.value))
}

/// Returns `true` if `self` is not equal to `other`. Otherwise, returns `false`.
public fun infix!= (_ other: Self) -> Bool {
Bool(value: Builtin.icmp_ne_i1(value, other.value))
}
}

public conformance Bool: Deinitializable {}

public conformance Bool: Movable {}

public conformance Bool: Copyable {

public fun copy() -> Self {
Bool(value: value)
}

}

public conformance Bool: Equatable {

public fun infix== (_ other: Self) -> Bool {
Bool(value: Builtin.icmp_eq_i1(value, other.value))
}

public fun infix!= (_ other: Self) -> Bool {
Bool(value: Builtin.icmp_ne_i1(value, other.value))
}

}

public conformance Bool: Regular {}
8 changes: 6 additions & 2 deletions Library/Hylo/Core/CollectionOfOne.hylo
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/// A collection containing a single element.
public type CollectionOfOne<Element: Movable & Deinitializable>: Deinitializable {

public typealias Index = Bool

/// The element contained in `self`.
var contents: Element

Expand All @@ -11,6 +9,12 @@ public type CollectionOfOne<Element: Movable & Deinitializable>: Deinitializable
&self.contents = contents
}

}

public conformance CollectionOfOne: Collection {

public typealias Index = Bool

public fun start_index() -> Bool { false }

public fun end_index() -> Bool { true }
Expand Down
21 changes: 21 additions & 0 deletions Library/Hylo/Core/Iterator.hylo
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// A type that supplies the elements of a list one at a type.
///
/// An iterator encapsulates the necessary state and logic to produce the elements of a possibly
/// unbounded list, one after the other. Elements are returned by `next()`, which returns either
/// the next element in the list or `None` if all elements have been returned.
///
/// Use `Iterator` to implement single-pass iteration algorithms that take ownership of the values
/// on which they iterate. You can "step through" the elements of an iterator using a for-loop:
///
/// for let x in some_iterator { print(x) }
///
/// An `Iterator` typically does not model a `Collection`.
public trait Iterator {

/// The type of the elements produced by `Self`.
type Element

/// Advances to the next element and returns it, or `None` if no next element exists.
fun next() inout -> Optional<Element>

}
4 changes: 4 additions & 0 deletions Library/Hylo/Core/Numbers/Integers/Int.hylo
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public conformance Int: ExpressibleByIntegerLiteral {}

public conformance Int: Deinitializable {}

public conformance Int: Movable {}

public conformance Int: Copyable {

public fun copy() -> Self {
Expand All @@ -72,6 +74,8 @@ public conformance Int: Equatable {

}

public conformance Int: Regular {}

public conformance Int: Comparable {

public fun infix< (_ other: Self) -> Bool {
Expand Down
2 changes: 1 addition & 1 deletion Library/Hylo/Core/Regular.hylo
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ public trait SemiRegular: Deinitializable, Movable, Equatable {}
/// Regular types (roughly per Stepanov).
///
/// Copies have equal value.
public trait Regular: Deinitializable, Copyable, Movable, Equatable {}
public trait Regular: SemiRegular, Copyable {}
2 changes: 1 addition & 1 deletion Sources/Core/AST/Decl/ConformanceDecl.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// A declaration that extends a type with new conformances.
public struct ConformanceDecl: TypeExtendingDecl {
public struct ConformanceDecl: ConformanceSource, TypeExtendingDecl {

public static let constructDescription = "conformance declaration"

Expand Down
7 changes: 7 additions & 0 deletions Sources/Core/AST/Decl/ConformanceSource.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// The declaration of a type's conformance to one or multiple traits.
public protocol ConformanceSource: ExposableDecl {

/// The names of traits to which the type conforms.
var conformances: [NameExpr.ID] { get }

}
2 changes: 1 addition & 1 deletion Sources/Core/AST/Decl/ProductTypeDecl.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// A (nominal) product type declaration.
public struct ProductTypeDecl: ExposableDecl, GenericDecl, SingleEntityDecl, GenericScope {
public struct ProductTypeDecl: ConformanceSource, GenericDecl, SingleEntityDecl, GenericScope {

public static let constructDescription = "product type declaration"

Expand Down
6 changes: 6 additions & 0 deletions Sources/Core/AST/Pattern/BindingPattern.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Utils
/// bindings, instead of referring to existing declarations.
public struct BindingPattern: Pattern {

/// An introducer in a binding pattern.
public enum Introducer: Codable {

case `let`
Expand All @@ -16,6 +17,11 @@ public struct BindingPattern: Pattern {

case `inout`

/// `true` if `self` is `var` or `sinklet`.
public var isConsuming: Bool {
(self == .var) || (self == .sinklet)
}

}

public let site: SourceRange
Expand Down
16 changes: 16 additions & 0 deletions Sources/Core/ConformanceOrigin.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// The declaration and site from which an explicit conformance originates.
public struct ConformanceOrigin {

/// The declaration of the conformance.
public let source: AnyDeclID

/// The site at which diagnostics related to the conformance are reported.
public let site: SourceRange

/// Creates an instance with the given properties.
public init<T: ConformanceSource>(_ source: T.ID, at site: SourceRange) {
self.source = AnyDeclID(source)
self.site = site
}

}
31 changes: 31 additions & 0 deletions Sources/FrontEnd/TypeChecking/BindingDeclUse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Core

/// How a binding declaration is being used.
enum BindingDeclUse: Hashable {

/// The declaration is used to introduce new bindings unconditionally.
///
/// The pattern matches any possible value produced by the declaration's initializer, if present.
case irrefutable

/// The declaration is used as a condition.
///
/// The pattern acts as a condition that is satisfied iff it matches the value of the
/// declaration's initializer, which must be present.
case condition

/// The declaration is used as a filter.
///
/// The pattern acts as a condition that is satisfied iff it matches an instance of the payload.
case filter(matching: AnyType)

/// The type that is narrowed by the pattern of the declaration if it is used as a filter.
var filteredType: AnyType? {
if case .filter(let t) = self {
return t
} else {
return nil
}
}

}
12 changes: 12 additions & 0 deletions Sources/FrontEnd/TypeChecking/TypeChecker+Diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,18 @@ extension Diagnostic {
.error("right operand of built-in pointer conversion must be a remote type", at: site)
}

static func error(
invalidForLoopDomain m: AnyType, consuming: Bool, at site: SourceRange
) -> Diagnostic {
if consuming {
return .error(
"consuming for loop requires '\(m)' to conform to 'Iterator'", at: site)
} else {
return .error(
"non-consuming for loop requires '\(m)' to conform to 'Collection' or 'Iterator'", at: site)
}
}

static func warning(needlessImport d: ImportDecl.ID, in ast: AST) -> Diagnostic {
let s = ast[d].identifier
return .warning("needless import: source file is part of '\(s.value)'", at: s.site)
Expand Down
Loading

0 comments on commit ad2a3c6

Please sign in to comment.