namespace swift {

class ASTContext;
class TypeRepr;

/// TypeLoc - Provides source location information for a parsed type.
/// A TypeLoc is stored in AST nodes which use an explicitly written type.
class alignas(1 << TypeLocAlignInBits) TypeLoc {
  Type Ty;
  TypeRepr *TyR = nullptr;

public:
  TypeLoc() {}
  TypeLoc(TypeRepr *TyR) : TyR(TyR) {}
  TypeLoc(TypeRepr *TyR, Type Ty) : TyR(TyR) {
    setType(Ty);
  }

  bool wasValidated() const { return !Ty.isNull(); }
  bool isError() const;

  // FIXME: We generally shouldn't need to build TypeLocs without a location.
  static TypeLoc withoutLoc(Type T) {
    TypeLoc result;
    result.Ty = T;
    return result;
  }

  /// Get the representative location of this type, for diagnostic
  /// purposes.
  /// This location is not necessarily the start location of the type repr.
  SourceLoc getLoc() const;
  SourceRange getSourceRange() const;

  bool hasLocation() const { return TyR != nullptr; }
  TypeRepr *getTypeRepr() const { return TyR; }
  Type getType() const { return Ty; }

  bool isNull() const { return getType().isNull() && TyR == nullptr; }

  void setInvalidType(ASTContext &C);
  void setType(Type Ty);

  TypeLoc clone(ASTContext &ctx) const;
  
  friend llvm::hash_code hash_value(const TypeLoc &owner) {
    return llvm::hash_combine(owner.Ty.getPointer(), owner.TyR);
  }

  friend bool operator==(const TypeLoc &lhs,
                         const TypeLoc &rhs) {
    return lhs.Ty.getPointer() == rhs.Ty.getPointer()
        && lhs.TyR == rhs.TyR;
  }

  friend bool operator!=(const TypeLoc &lhs,
                         const TypeLoc &rhs) {
    return !(lhs == rhs);
  }
};

} // end namespace llvm

#endif
